summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2011-06-08 23:01:28 -0700
committerJim Miller <jaggies@google.com>2011-06-10 18:02:29 -0700
commitb505074e8273887fbcd1e933738a42e770085fb8 (patch)
treeab7bc23f88ef01d51028fca8afab9200bfe9bb37
parentd408f4a8353e679dab2016e56ed237309d8a7523 (diff)
downloadframeworks_base-b505074e8273887fbcd1e933738a42e770085fb8.zip
frameworks_base-b505074e8273887fbcd1e933738a42e770085fb8.tar.gz
frameworks_base-b505074e8273887fbcd1e933738a42e770085fb8.tar.bz2
Add new MultiWaveView widget and integrate it into LockScreen
This adds a new multi-target widget to the framework and integrates it into LockScreen. Now with updated assets. Change-Id: Ib41595b9e80a7be6d647f44c803a77f9e5bfeca9
-rw-r--r--api/current.txt12
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/Ease.java132
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java645
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java215
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/Tweener.java132
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_answer_active.pngbin0 -> 9066 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.pngbin0 -> 17982 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.pngbin0 -> 6412 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.pngbin0 -> 665 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.pngbin0 -> 665 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.pngbin0 -> 8327 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.pngbin0 -> 16563 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.pngbin0 -> 5387 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.pngbin0 -> 3020 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.pngbin0 -> 8376 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.pngbin0 -> 3020 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.pngbin0 -> 8376 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_outerring.pngbin0 -> 9454 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.pngbin0 -> 7649 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.pngbin0 -> 12968 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.pngbin0 -> 5716 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.pngbin0 -> 7114 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.pngbin0 -> 12774 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.pngbin0 -> 5172 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_text_activated.pngbin0 -> 6357 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.pngbin0 -> 9620 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_text_normal.pngbin0 -> 1713 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.pngbin0 -> 6429 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.pngbin0 -> 9323 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.pngbin0 -> 1347 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_answer_active.pngbin0 -> 5554 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.pngbin0 -> 10251 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.pngbin0 -> 3732 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.pngbin0 -> 533 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.pngbin0 -> 534 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.pngbin0 -> 5114 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.pngbin0 -> 9202 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.pngbin0 -> 3028 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.pngbin0 -> 1883 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.pngbin0 -> 4800 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.pngbin0 -> 1883 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.pngbin0 -> 4800 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_outerring.pngbin0 -> 5840 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.pngbin0 -> 4462 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.pngbin0 -> 7048 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.pngbin0 -> 3123 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.pngbin0 -> 4231 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.pngbin0 -> 7042 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.pngbin0 -> 2871 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_text_activated.pngbin0 -> 3872 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.pngbin0 -> 5583 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_text_normal.pngbin0 -> 1182 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.pngbin0 -> 3941 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.pngbin0 -> 5437 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.pngbin0 -> 1006 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.pngbin0 -> 13057 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.pngbin0 -> 26181 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.pngbin0 -> 9504 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.pngbin0 -> 840 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.pngbin0 -> 844 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.pngbin0 -> 11903 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.pngbin0 -> 23969 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.pngbin0 -> 7480 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.pngbin0 -> 4173 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.pngbin0 -> 12221 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_outerring.pngbin0 -> 13636 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.pngbin0 -> 11341 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.pngbin0 -> 19515 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.pngbin0 -> 8633 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.pngbin0 -> 10439 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.pngbin0 -> 19513 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.pngbin0 -> 7698 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.pngbin0 -> 9196 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.pngbin0 -> 13914 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.pngbin0 -> 2232 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.pngbin0 -> 9353 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.pngbin0 -> 13386 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.pngbin0 -> 1759 bytes
-rw-r--r--core/res/res/drawable/ic_lockscreen_answer.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_decline.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_handle.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_send_sms.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_silent.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_soundon.xml30
-rw-r--r--core/res/res/drawable/ic_lockscreen_unlock.xml30
-rw-r--r--core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml2
-rw-r--r--core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml3
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock.xml24
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock_land.xml25
-rw-r--r--core/res/res/values-land/arrays.xml37
-rw-r--r--core/res/res/values/arrays.xml15
-rwxr-xr-xcore/res/res/values/attrs.xml44
-rw-r--r--core/res/res/values/dimens.xml9
-rw-r--r--core/res/res/values/public.xml13
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java135
95 files changed, 1596 insertions, 57 deletions
diff --git a/api/current.txt b/api/current.txt
index aed11b0..63771b9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -425,6 +425,7 @@ package android {
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
+ field public static final int feedbackCount = 16843665; // 0x1010391
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillEnabled = 16843343; // 0x101024f
@@ -478,6 +479,7 @@ package android {
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
+ field public static final int handleDrawable = 16843657; // 0x1010389
field public static final int handleProfiling = 16842786; // 0x1010022
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
field public static final int hardwareAccelerated = 16843475; // 0x10102d3
@@ -486,10 +488,12 @@ package android {
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
field public static final int hint = 16843088; // 0x1010150
+ field public static final int hitRadius = 16843662; // 0x101038e
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
field public static final int horizontalDivider = 16843053; // 0x101012d
field public static final int horizontalGap = 16843327; // 0x101023f
+ field public static final int horizontalOffset = 16843667; // 0x1010393
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
@@ -610,6 +614,7 @@ package android {
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
+ field public static final int leftChevronDrawable = 16843658; // 0x101038a
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -681,6 +686,7 @@ package android {
field public static final int orderingFromXml = 16843239; // 0x10101e7
field public static final int orientation = 16842948; // 0x10100c4
field public static final int outAnimation = 16843128; // 0x1010178
+ field public static final int outerRadius = 16843661; // 0x101038d
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
@@ -769,6 +775,7 @@ package android {
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
field public static final int right = 16843183; // 0x10101af
+ field public static final int rightChevronDrawable = 16843659; // 0x101038b
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
@@ -844,6 +851,7 @@ package android {
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
+ field public static final int snapMargin = 16843664; // 0x1010390
field public static final int soundEffectsEnabled = 16843285; // 0x1010215
field public static final int spacing = 16843027; // 0x1010113
field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087
@@ -908,6 +916,7 @@ package android {
field public static final int tag = 16842961; // 0x10100d1
field public static final int targetActivity = 16843266; // 0x1010202
field public static final int targetClass = 16842799; // 0x101002f
+ field public static final int targetDrawables = 16843656; // 0x1010388
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
@@ -1026,8 +1035,10 @@ package android {
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
field public static final int verticalGap = 16843328; // 0x1010240
+ field public static final int verticalOffset = 16843666; // 0x1010392
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
+ field public static final int vibrationDuration = 16843663; // 0x101038f
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1044,6 +1055,7 @@ package android {
field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298
field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293
field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294
+ field public static final int waveDrawable = 16843660; // 0x101038c
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
diff --git a/core/java/com/android/internal/widget/multiwaveview/Ease.java b/core/java/com/android/internal/widget/multiwaveview/Ease.java
new file mode 100644
index 0000000..7f90c44
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/Ease.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import android.animation.TimeInterpolator;
+
+class Ease {
+ private static final float DOMAIN = 1.0f;
+ private static final float DURATION = 1.0f;
+ private static final float START = 0.0f;
+
+ static class Linear {
+ public static final TimeInterpolator easeNone = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return input;
+ }
+ };
+ }
+
+ static class Cubic {
+ public static final TimeInterpolator easeIn = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN*(input/=DURATION)*input*input + START;
+ }
+ };
+ public static final TimeInterpolator easeOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START;
+ }
+ };
+ public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return ((input/=DURATION/2) < 1.0f) ?
+ (DOMAIN/2*input*input*input + START)
+ : (DOMAIN/2*((input-=2)*input*input + 2) + START);
+ }
+ };
+ }
+
+ static class Quad {
+ public static final TimeInterpolator easeIn = new TimeInterpolator() {
+ public float getInterpolation (float input) {
+ return DOMAIN*(input/=DURATION)*input + START;
+ }
+ };
+ public static final TimeInterpolator easeOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return -DOMAIN *(input/=DURATION)*(input-2) + START;
+ }
+ };
+ public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return ((input/=DURATION/2) < 1) ?
+ (DOMAIN/2*input*input + START)
+ : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START);
+ }
+ };
+ }
+
+ static class Quart {
+ public static final TimeInterpolator easeIn = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN*(input/=DURATION)*input*input*input + START;
+ }
+ };
+ public static final TimeInterpolator easeOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START;
+ }
+ };
+ public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return ((input/=DURATION/2) < 1) ?
+ (DOMAIN/2*input*input*input*input + START)
+ : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START);
+ }
+ };
+ }
+
+ static class Quint {
+ public static final TimeInterpolator easeIn = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN*(input/=DURATION)*input*input*input*input + START;
+ }
+ };
+ public static final TimeInterpolator easeOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START;
+ }
+ };
+ public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return ((input/=DURATION/2) < 1) ?
+ (DOMAIN/2*input*input*input*input*input + START)
+ : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START);
+ }
+ };
+ }
+
+ static class Sine {
+ public static final TimeInterpolator easeIn = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START;
+ }
+ };
+ public static final TimeInterpolator easeOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START;
+ }
+ };
+ public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+ public float getInterpolation(float input) {
+ return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START;
+ }
+ };
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
new file mode 100644
index 0000000..026ad27
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import java.util.ArrayList;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * A special widget containing a center and outer ring. Moving the center ring to the outer ring
+ * causes an event that can be caught by implementing OnTriggerListener.
+ */
+public class MultiWaveView extends View implements AnimatorUpdateListener {
+ private static final String TAG = "MultiWaveView";
+ private static final boolean DEBUG = false;
+
+ // Wave state machine
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_FIRST_TOUCH = 1;
+ private static final int STATE_TRACKING = 2;
+ private static final int STATE_SNAP = 3;
+ private static final int STATE_FINISH = 4;
+
+ // Animation properties.
+ private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it
+
+ public interface OnTriggerListener {
+ int NO_HANDLE = 0;
+ int CENTER_HANDLE = 1;
+ public void onGrabbed(View v, int handle);
+ public void onReleased(View v, int handle);
+ public void onTrigger(View v, int target);
+ public void onGrabbedStateChange(View v, int handle);
+ }
+
+ // Tune-able parameters
+ private static final int CHEVRON_INCREMENTAL_DELAY = 50;
+ private static final int CHEVRON_ANIMATION_DURATION = 1000;
+ private static final int RETURN_TO_HOME_DURATION = 150;
+ private static final int HIDE_ANIMATION_DELAY = 500;
+ private static final int HIDE_ANIMATION_DURACTION = 2000;
+ private static final int SHOW_ANIMATION_DURATION = 0;
+ private static final int SHOW_ANIMATION_DELAY = 0;
+ private TimeInterpolator mChevronAnimationInterpolator = Ease.Quint.easeOut;
+
+ private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
+ private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
+ private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
+ private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>();
+ private Tweener mHandleAnimation;
+ private OnTriggerListener mOnTriggerListener;
+ private TargetDrawable mHandleDrawable;
+ private TargetDrawable mOuterRing;
+ private Vibrator mVibrator;
+
+ private int mFeedbackCount = 3;
+ private int mVibrationDuration = 0;
+ private int mGrabbedState;
+ private int mActiveTarget = -1;
+ private float mTapRadius;
+ private float mWaveCenterX;
+ private float mWaveCenterY;
+ private float mVerticalOffset;
+ private float mHorizontalOffset;
+ private float mOuterRadius = 0.0f;
+ private float mHitRadius = 0.0f;
+ private float mSnapMargin = 0.0f;
+ private boolean mDragging;
+
+ private AnimatorListener mResetListener = new Animator.AnimatorListener() {
+ public void onAnimationStart(Animator animation) { }
+ public void onAnimationRepeat(Animator animation) { }
+ public void onAnimationEnd(Animator animation) {
+ switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+ }
+ public void onAnimationCancel(Animator animation) { }
+ };
+
+ public MultiWaveView(Context context) {
+ this(context, null);
+ }
+
+ public MultiWaveView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ Resources res = context.getResources();
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView);
+ mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius);
+ mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset,
+ mHorizontalOffset);
+ mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset,
+ mVerticalOffset);
+ mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius);
+ mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin);
+ mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration,
+ mVibrationDuration);
+ mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount,
+ mFeedbackCount);
+ mHandleDrawable = new TargetDrawable(res,
+ a.getDrawable(R.styleable.MultiWaveView_handleDrawable));
+ mTapRadius = mHandleDrawable.getWidth()/2;
+ mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable));
+
+ // Read animation drawables
+ Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable);
+ if (leftChevron != null) {
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(new TargetDrawable(res, leftChevron));
+ }
+ }
+ Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable);
+ if (rightChevron != null) {
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(new TargetDrawable(res, rightChevron));
+ }
+ }
+
+ // Read array of target drawables
+ TypedValue outValue = new TypedValue();
+ if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) {
+ setTargetResources(outValue.resourceId);
+ }
+ if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
+ throw new IllegalStateException("Must specify at least one target drawable");
+ }
+
+ setVibrateEnabled(mVibrationDuration > 0);
+ }
+
+ private void dump() {
+ Log.v(TAG, "Outer Radius = " + mOuterRadius);
+ Log.v(TAG, "HitRadius = " + mHitRadius);
+ Log.v(TAG, "SnapMargin = " + mSnapMargin);
+ Log.v(TAG, "FeedbackCount = " + mFeedbackCount);
+ Log.v(TAG, "VibrationDuration = " + mVibrationDuration);
+ Log.v(TAG, "TapRadius = " + mTapRadius);
+ Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
+ Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
+ Log.v(TAG, "HorizontalOffset = " + mHorizontalOffset);
+ Log.v(TAG, "VerticalOffset = " + mVerticalOffset);
+ }
+
+ @Override
+ protected int getSuggestedMinimumWidth() {
+ // View should be large enough to contain the background + target drawable on either edge
+ return mOuterRing.getWidth()
+ + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getWidth()) : 0);
+ }
+
+ @Override
+ protected int getSuggestedMinimumHeight() {
+ // View should be large enough to contain the unlock ring + target drawable on either edge
+ return mOuterRing.getHeight()
+ + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getHeight()) : 0);
+ }
+
+ private void switchToState(int state, float x, float y) {
+ switch (state) {
+ case STATE_IDLE:
+ stopChevronAnimation();
+ deactivateTargets();
+ mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+ break;
+
+ case STATE_FIRST_TOUCH:
+ stopHandleAnimation();
+ deactivateTargets();
+ showTargets();
+ mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
+ setGrabbedState(OnTriggerListener.CENTER_HANDLE);
+ break;
+
+ case STATE_TRACKING:
+ break;
+
+ case STATE_SNAP:
+ break;
+
+ case STATE_FINISH:
+ doFinish();
+ break;
+ }
+ }
+
+ /**
+ * Animation used to attract user's attention to the target button.
+ * Assumes mChevronDrawables is an a list with an even number of chevrons filled with left
+ * followed by right chevrons.
+ */
+ private void startChevronAnimation() {
+ final int icons = mChevronDrawables.size();
+ for (Tweener tween : mChevronAnimations) {
+ tween.animator.cancel();
+ }
+ for (int i = 0; i < icons; i++) {
+ TargetDrawable icon = mChevronDrawables.get(i);
+ icon.setY(mWaveCenterY);
+ icon.setAlpha(1.0f);
+ mChevronAnimations.clear();
+ int delay = (int) (Math.abs(0.5f + i - icons / 2) * CHEVRON_INCREMENTAL_DELAY);
+ if (i < icons/2) {
+ // Left chevrons
+ icon.setX(mWaveCenterX - mHandleDrawable.getWidth() / 2);
+ mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
+ "ease", mChevronAnimationInterpolator,
+ "delay", delay,
+ "x", mWaveCenterX - mOuterRadius,
+ "alpha", 0.0f,
+ "onUpdate", this));
+ } else {
+ // Right chevrons
+ icon.setX(mWaveCenterX + mHandleDrawable.getWidth() / 2);
+ mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
+ "ease", mChevronAnimationInterpolator,
+ "delay", delay,
+ "x", mWaveCenterX + mOuterRadius,
+ "alpha", 0.0f,
+ "onUpdate", this));
+ }
+ }
+ }
+
+ private void stopChevronAnimation() {
+ for (Tweener anim : mChevronAnimations) {
+ anim.animator.end();
+ }
+ mChevronAnimations.clear();
+ }
+
+ private void stopHandleAnimation() {
+ if (mHandleAnimation != null) {
+ mHandleAnimation.animator.end();
+ mHandleAnimation = null;
+ }
+ }
+
+ private void deactivateTargets() {
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ }
+ mActiveTarget = -1;
+ }
+
+ void invalidateGlobalRegion(TargetDrawable drawable) {
+ int width = drawable.getWidth();
+ int height = drawable.getHeight();
+ RectF childBounds = new RectF(0, 0, width, height);
+ childBounds.offset(drawable.getX() - width/2, drawable.getY() - height/2);
+ View view = this;
+ while (view.getParent() != null && view.getParent() instanceof View) {
+ view = (View) view.getParent();
+ view.getMatrix().mapRect(childBounds);
+ view.invalidate((int) Math.floor(childBounds.left),
+ (int) Math.floor(childBounds.top),
+ (int) Math.ceil(childBounds.right),
+ (int) Math.ceil(childBounds.bottom));
+ }
+ }
+
+ /**
+ * Dispatches a trigger event to listener. Ignored if a listener is not set.
+ * @param whichHandle the handle that triggered the event.
+ */
+ private void dispatchTriggerEvent(int whichHandle) {
+ vibrate();
+ if (mOnTriggerListener != null) {
+ mOnTriggerListener.onTrigger(this, whichHandle);
+ }
+ }
+
+ private void doFinish() {
+ // Inform listener of any active targets. Typically only one will be active.
+ final int activeTarget = mActiveTarget;
+ boolean targetHit = activeTarget != -1;
+ if (targetHit) {
+ Log.v(TAG, "Finish with target hit = " + targetHit);
+ dispatchTriggerEvent(mActiveTarget);
+ }
+
+ setGrabbedState(OnTriggerListener.NO_HANDLE);
+
+ // Animate finger outline back to home position
+ mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
+ mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION,
+ "ease", Ease.Quart.easeOut,
+ "delay", targetHit ? HIDE_ANIMATION_DELAY : 0,
+ "alpha", 1.0f,
+ "x", mWaveCenterX,
+ "y", mWaveCenterY,
+ "onUpdate", this,
+ "onComplete", mResetListener);
+
+ // Hide unselected targets
+ hideTargets(true);
+
+ // Highlight the selected one
+ if (targetHit) {
+ mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
+ }
+
+ stopChevronAnimation();
+ }
+
+ private void hideTargets(boolean animate) {
+ if (mTargetAnimations.size() > 0) {
+ stopTargetAnimation();
+ }
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ mTargetAnimations.add(Tweener.to(target,
+ animate ? HIDE_ANIMATION_DURACTION : 0,
+ "alpha", 0.0f,
+ "delay", HIDE_ANIMATION_DELAY,
+ "onUpdate", this));
+ }
+ mTargetAnimations.add(Tweener.to(mOuterRing,
+ animate ? HIDE_ANIMATION_DURACTION : 0,
+ "alpha", 0.0f,
+ "delay", HIDE_ANIMATION_DELAY,
+ "onUpdate", this));
+ }
+
+ private void showTargets() {
+ if (mTargetAnimations.size() > 0) {
+ stopTargetAnimation();
+ }
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION,
+ "alpha", 1.0f,
+ "delay", SHOW_ANIMATION_DELAY,
+ "onUpdate", this));
+ }
+ mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION,
+ "alpha", 1.0f,
+ "delay", SHOW_ANIMATION_DELAY,
+ "onUpdate", this));
+ }
+
+ private void stopTargetAnimation() {
+ for (Tweener anim : mTargetAnimations) {
+ anim.animator.end();
+ }
+ mTargetAnimations.clear();
+ }
+
+ private void vibrate() {
+ if (mVibrator != null) {
+ mVibrator.vibrate(mVibrationDuration);
+ }
+ }
+
+ /**
+ * Loads an array of drawables from the given resourceId.
+ *
+ * @param resourceId
+ */
+ public void setTargetResources(int resourceId) {
+ Resources res = getContext().getResources();
+ TypedArray array = res.obtainTypedArray(resourceId);
+ int count = array.length();
+ mTargetDrawables = new ArrayList<TargetDrawable>(count);
+ for (int i = 0; i < count; i++) {
+ Drawable drawable = array.getDrawable(i);
+ mTargetDrawables.add(new TargetDrawable(res, drawable));
+ }
+ }
+
+ /**
+ * Enable or disable vibrate on touch.
+ *
+ * @param enabled
+ */
+ public void setVibrateEnabled(boolean enabled) {
+ if (enabled && mVibrator == null) {
+ mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ } else {
+ mVibrator = null;
+ }
+ }
+
+ /**
+ * Starts chevron animation. Example use case: show chevron animation whenever the phone rings
+ * or the user touches the screen.
+ *
+ */
+ public void ping() {
+ stopChevronAnimation();
+ startChevronAnimation();
+ }
+
+ /**
+ * Resets the widget to default state and cancels all animation. If animate is 'true', will
+ * animate objects into place. Otherwise, objects will snap back to place.
+ *
+ * @param animate
+ */
+ public void reset(boolean animate) {
+ stopChevronAnimation();
+ stopHandleAnimation();
+ stopTargetAnimation();
+ hideChevrons();
+ hideTargets(animate);
+ mHandleDrawable.setX(mWaveCenterX);
+ mHandleDrawable.setY(mWaveCenterY);
+ mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final int action = event.getAction();
+
+ boolean handled = false;
+ float x = event.getX();
+ float y = event.getY();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ handleDown(x, y);
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ handleMove(x, y);
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_UP:
+ handleUp(x, y);
+ handleMove(x, y);
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ handleMove(x, y);
+ handled = true;
+ break;
+ }
+ invalidate();
+ return handled ? true : super.onTouchEvent(event);
+ }
+
+ private void handleDown(float x, float y) {
+ final float dx = x - mWaveCenterX;
+ final float dy = y - mWaveCenterY;
+ if (dist2(dx,dy) <= square(mTapRadius)) {
+ if (DEBUG) Log.v(TAG, "** Handle HIT");
+ switchToState(STATE_FIRST_TOUCH, x, y);
+ mDragging = true;
+ } else {
+ mDragging = false;
+ stopTargetAnimation();
+ ping();
+ }
+ }
+
+ private void handleUp(float x, float y) {
+ if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
+ switchToState(STATE_FINISH, x, y);
+ }
+
+ private void handleMove(float x, float y) {
+ if (!mDragging) {
+ return;
+ }
+
+ float tx = x - mWaveCenterX;
+ float ty = y - mWaveCenterY;
+ float touchRadius = (float) Math.sqrt(dist2(tx, ty));
+ final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
+ float limitX = mWaveCenterX + tx * scale;
+ float limitY = mWaveCenterY + ty * scale;
+
+ int activeTarget = -1;
+ boolean singleTarget = mTargetDrawables.size() == 1;
+ if (singleTarget) {
+ // Snap to outer ring if there's only one target
+ float snapRadius = mOuterRadius - mSnapMargin;
+ if (touchRadius > snapRadius) {
+ activeTarget = 0;
+ x = limitX;
+ y = limitY;
+ }
+ } else {
+ // If there's more than one target, snap to the closest one less than hitRadius away.
+ float best = Float.MAX_VALUE;
+ final float hitRadius2 = mHitRadius * mHitRadius;
+ for (int i = 0; i < mTargetDrawables.size(); i++) {
+ // Snap to the first target in range
+ TargetDrawable target = mTargetDrawables.get(i);
+ float dx = limitX - target.getX();
+ float dy = limitY - target.getY();
+ float dist2 = dx*dx + dy*dy;
+ if (target.isValid() && dist2 < hitRadius2 && dist2 < best) {
+ activeTarget = i;
+ best = dist2;
+ }
+ }
+ }
+ if (activeTarget != -1) {
+ switchToState(STATE_SNAP, x,y);
+ mHandleDrawable.setX(singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX());
+ mHandleDrawable.setY(singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY());
+ TargetDrawable currentTarget = mTargetDrawables.get(activeTarget);
+ if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) {
+ currentTarget.setState(TargetDrawable.STATE_FOCUSED);
+ mHandleDrawable.setAlpha(0.0f);
+ }
+ } else {
+ switchToState(STATE_TRACKING, x, y);
+ mHandleDrawable.setX(x);
+ mHandleDrawable.setY(y);
+ mHandleDrawable.setAlpha(1.0f);
+ }
+ // Draw handle outside parent's bounds
+ invalidateGlobalRegion(mHandleDrawable);
+
+ if (mActiveTarget != activeTarget && activeTarget != -1) {
+ vibrate();
+ }
+ mActiveTarget = activeTarget;
+ }
+
+ /**
+ * Sets the current grabbed state, and dispatches a grabbed state change
+ * event to our listener.
+ */
+ private void setGrabbedState(int newState) {
+ if (newState != mGrabbedState) {
+ if (newState != OnTriggerListener.NO_HANDLE) {
+ vibrate();
+ }
+ mGrabbedState = newState;
+ if (mOnTriggerListener != null) {
+ mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
+ }
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ final int width = right - left;
+ final int height = bottom - top;
+
+ mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
+ mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
+ mHandleDrawable.setX(mWaveCenterX);
+ mHandleDrawable.setY(mWaveCenterY);
+ mOuterRing.setX(mWaveCenterX);
+ mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
+ mOuterRing.setAlpha(0.0f);
+ if (mOuterRadius == 0.0f) {
+ mOuterRadius = 0.5f*(float) Math.sqrt(dist2(mWaveCenterX, mWaveCenterY));
+ }
+ if (mHitRadius == 0.0f) {
+ // Use the radius of inscribed circle of the first target.
+ mHitRadius = mTargetDrawables.get(0).getWidth() / 2.0f;
+ }
+ if (mSnapMargin == 0.0f) {
+ mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
+ }
+ for (int i = 0; i < mTargetDrawables.size(); i++) {
+ final TargetDrawable targetIcon = mTargetDrawables.get(i);
+ double angle = -2.0f * Math.PI * i / mTargetDrawables.size();
+ float xPosition = mWaveCenterX + mOuterRadius * (float) Math.cos(angle);
+ float yPosition = mWaveCenterY + mOuterRadius * (float) Math.sin(angle);
+ targetIcon.setX(xPosition);
+ targetIcon.setY(yPosition);
+ targetIcon.setAlpha(0.0f);
+ }
+ hideChevrons();
+ hideTargets(false);
+ if (DEBUG) dump();
+ }
+
+ private void hideChevrons() {
+ for (TargetDrawable chevron : mChevronDrawables) {
+ chevron.setAlpha(0.0f);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mOuterRing.draw(canvas);
+ for (TargetDrawable target : mTargetDrawables) {
+ target.draw(canvas);
+ }
+ for (TargetDrawable target : mChevronDrawables) {
+ target.draw(canvas);
+ }
+ mHandleDrawable.draw(canvas);
+ }
+
+ public void setOnTriggerListener(OnTriggerListener listener) {
+ mOnTriggerListener = listener;
+ }
+
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateGlobalRegion(mHandleDrawable);
+ invalidate();
+ }
+
+ private float square(float d) {
+ return d * d;
+ }
+
+ private float dist2(float dx, float dy) {
+ return dx*dx + dy*dy;
+ }
+
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
new file mode 100644
index 0000000..d3baa2b
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.util.Log;
+
+public class TargetDrawable {
+ private static final String TAG = "TargetDrawable";
+ public static final int[] STATE_ACTIVE =
+ { android.R.attr.state_enabled, android.R.attr.state_active };
+ public static final int[] STATE_INACTIVE =
+ { android.R.attr.state_enabled, -android.R.attr.state_active };
+ public static final int[] STATE_FOCUSED =
+ { android.R.attr.state_enabled, android.R.attr.state_focused };
+
+ private float mTranslationX = 0.0f;
+ private float mTranslationY = 0.0f;
+ private float mScaleX = 1.0f;
+ private float mScaleY = 1.0f;
+ private float mAlpha = 1.0f;
+ private Drawable mDrawable;
+
+ /* package */ static class DrawableWithAlpha extends Drawable {
+ private float mAlpha = 1.0f;
+ private Drawable mRealDrawable;
+ public DrawableWithAlpha(Drawable realDrawable) {
+ mRealDrawable = realDrawable;
+ }
+ public void setAlpha(float alpha) {
+ mAlpha = alpha;
+ }
+ public float getAlpha() {
+ return mAlpha;
+ }
+ public void draw(Canvas canvas) {
+ mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f));
+ mRealDrawable.draw(canvas);
+ }
+ @Override
+ public void setAlpha(int alpha) {
+ mRealDrawable.setAlpha(alpha);
+ }
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mRealDrawable.setColorFilter(cf);
+ }
+ @Override
+ public int getOpacity() {
+ return mRealDrawable.getOpacity();
+ }
+ }
+
+ public TargetDrawable(Resources res, int resId) {
+ this(res, resId == 0 ? null : res.getDrawable(resId));
+ }
+
+ public TargetDrawable(Resources res, Drawable drawable) {
+ // Mutate the drawable so we can animate shared drawable properties.
+ mDrawable = drawable != null ? drawable.mutate() : null;
+ resizeDrawables();
+ setState(STATE_INACTIVE);
+ }
+
+ public void setState(int [] state) {
+ if (mDrawable instanceof StateListDrawable) {
+ StateListDrawable d = (StateListDrawable) mDrawable;
+ d.setState(state);
+ }
+ }
+
+ public boolean hasState(int [] state) {
+ if (mDrawable instanceof StateListDrawable) {
+ StateListDrawable d = (StateListDrawable) mDrawable;
+ // TODO: this doesn't seem to work
+ return d.getStateDrawableIndex(state) != -1;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the drawable is a StateListDrawable and is in the focused state.
+ *
+ * @return
+ */
+ public boolean isActive() {
+ if (mDrawable instanceof StateListDrawable) {
+ StateListDrawable d = (StateListDrawable) mDrawable;
+ int[] states = d.getState();
+ for (int i = 0; i < states.length; i++) {
+ if (states[i] == android.R.attr.state_focused) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this target is enabled. Typically an enabled target contains a valid
+ * drawable in a valid state. Currently all targets with valid drawables are valid.
+ *
+ * @return
+ */
+ public boolean isValid() {
+ return mDrawable != null;
+ }
+
+ /**
+ * Makes drawables in a StateListDrawable all the same dimensions.
+ * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
+ * drawable.
+ */
+ private void resizeDrawables() {
+ if (mDrawable instanceof StateListDrawable) {
+ StateListDrawable d = (StateListDrawable) mDrawable;
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (int i = 0; i < d.getStateCount(); i++) {
+ Drawable childDrawable = d.getStateDrawable(i);
+ maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
+ maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
+ }
+ Log.v(TAG, "union of childDrawable rects " + d + " to: " + maxWidth + "x" + maxHeight);
+ d.setBounds(0, 0, maxWidth, maxHeight);
+ for (int i = 0; i < d.getStateCount(); i++) {
+ Drawable childDrawable = d.getStateDrawable(i);
+ Log.v(TAG, "sizing drawable " + childDrawable + " to: " + maxWidth + "x" + maxHeight);
+ childDrawable.setBounds(0, 0, maxWidth, maxHeight);
+ }
+ } else if (mDrawable != null) {
+ mDrawable.setBounds(0, 0,
+ mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
+ }
+ }
+
+ public void setX(float x) {
+ mTranslationX = x;
+ }
+
+ public void setY(float y) {
+ mTranslationY = y;
+ }
+
+ public void setScaleX(float x) {
+ mScaleX = x;
+ }
+
+ public void setScaleY(float y) {
+ mScaleY = y;
+ }
+
+ public void setAlpha(float alpha) {
+ mAlpha = alpha;
+ }
+
+ public float getX() {
+ return mTranslationX;
+ }
+
+ public float getY() {
+ return mTranslationY;
+ }
+
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ public float getAlpha() {
+ return mAlpha;
+ }
+
+ public int getWidth() {
+ return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
+ }
+
+ public int getHeight() {
+ return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
+ }
+
+ public void draw(Canvas canvas) {
+ if (mDrawable == null) {
+ return;
+ }
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.translate(mTranslationX, mTranslationY);
+ canvas.scale(mScaleX, mScaleY);
+ canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
+ mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
+ mDrawable.draw(canvas);
+ canvas.restore();
+ }
+}
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
new file mode 100644
index 0000000..c2746d9
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+
+class Tweener {
+ private static final String TAG = "Tweener";
+
+ private Object object;
+ ObjectAnimator animator;
+ private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
+
+ public Tweener(Object obj, ObjectAnimator anim) {
+ object = obj;
+ animator = anim;
+ }
+
+ public static Tweener to(Object object, long duration, Object... vars) {
+ long delay = 0;
+ AnimatorUpdateListener updateListener = null;
+ AnimatorListener listener = null;
+ TimeInterpolator interpolator = null;
+
+ // Iterate through arguments and discover properties to animate
+ ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
+ for (int i = 0; i < vars.length; i+=2) {
+ if (!(vars[i] instanceof String)) {
+ throw new IllegalArgumentException("Key must be a string: " + vars[i]);
+ }
+ String key = (String) vars[i];
+ Object value = vars[i+1];
+ if ("simultaneousTween".equals(key)) {
+ // TODO
+ } else if ("ease".equals(key)) {
+ interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
+ } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
+ updateListener = (AnimatorUpdateListener) value;
+ } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
+ listener = (AnimatorListener) value;
+ } else if ("delay".equals(key)) {
+ delay = ((Number) value).longValue();
+ } else if ("syncWith".equals(key)) {
+ // TODO
+ } else if (value instanceof Number[]) {
+ // TODO: support Tween.from()
+ } else if (value instanceof Number) {
+ float floatValue = ((Number)value).floatValue();
+ props.add(PropertyValuesHolder.ofFloat(key, floatValue));
+ } else {
+ throw new IllegalArgumentException(
+ "Bad argument for key \"" + key + "with value" + value);
+ }
+ }
+
+ // Re-use existing tween, if present
+ Tweener tween = sTweens.get(object);
+ if (tween == null) {
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(object,
+ props.toArray(new PropertyValuesHolder[props.size()]));
+ tween = new Tweener(object, anim);
+ sTweens.put(object, tween);
+ } else {
+ tween.animator.cancel();
+ replace(props, object);
+ }
+
+ if (interpolator != null) {
+ tween.animator.setInterpolator(interpolator);
+ }
+
+ // Update animation with properties discovered in loop above
+ tween.animator.setStartDelay(delay);
+ tween.animator.setDuration(duration);
+ if (updateListener != null) {
+ tween.animator.removeAllUpdateListeners(); // There should be only one
+ tween.animator.addUpdateListener(updateListener);
+ }
+ if (listener != null) {
+ tween.animator.removeAllListeners(); // There should be only one.
+ tween.animator.addListener(listener);
+ }
+ tween.animator.start();
+
+ return tween;
+ }
+
+ Tweener from(Object object, long duration, Object... vars) {
+ // TODO: for v of vars
+ // toVars[v] = object[v]
+ // object[v] = vars[v]
+ return Tweener.to(object, duration, vars);
+ }
+
+ static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
+ for (final Object killobject : args) {
+ Tweener tween = sTweens.get(killobject);
+ if (tween != null) {
+ if (killobject == tween.object) {
+ tween.animator.cancel();
+ if (props != null) {
+ tween.animator.setValues(
+ props.toArray(new PropertyValuesHolder[props.size()]));
+ } else {
+ sTweens.remove(tween);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..8089912
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..e4ba8fd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..c9197c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..d008afa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..e508900
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..9866769
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..f5dfacc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..b4d399d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..e21a87c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..3283f99
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..732133c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..0bbf62f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..5294bc5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..fce4980
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..ecafbea
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..1f527b7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..73f01c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..d4e558d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..5d999a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..d01bdb2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..72b8f0a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..bf73a26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..d333946
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..e053222
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..7db46c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..0ad03c0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..f46e8bd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..ddeeb18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..e5ef113
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..ab723b7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..d1aae18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..b52c844
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..722027e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..c10344f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..08c6cfe
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..30eb974
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..aab2f6b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..4151f73
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..3b2f3fc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..6a5af9d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..c288ce4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..03f524d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..db59b5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..eb6ceed
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..dbfc5ba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..1de7586
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..e007322
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..df47993
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..6f51447
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..dd255f5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..8edf62d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..2a47e9b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..f049dc9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..75173cb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..9f6da72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..4244ca0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..a98a379
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..fa2a0f4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..c44a330
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..2264dc3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..0b4b260
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..fd81211
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..5a93472
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..73f6a2e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..9edc70b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..0485af0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..6af5375
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..29c4572
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..42c8ad2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..ff65f20
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..fa0be96
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..d067ab8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..1a53c63
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_answer.xml b/core/res/res/drawable/ic_lockscreen_answer.xml
new file mode 100644
index 0000000..b42fc2a
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_answer.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_answer_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_answer_active" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_decline.xml b/core/res/res/drawable/ic_lockscreen_decline.xml
new file mode 100644
index 0000000..65128a1
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_decline.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_decline_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_decline_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_handle.xml b/core/res/res/drawable/ic_lockscreen_handle.xml
new file mode 100644
index 0000000..e7b4a6e
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_handle.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_handle_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_handle_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_send_sms.xml b/core/res/res/drawable/ic_lockscreen_send_sms.xml
new file mode 100644
index 0000000..2503a5c
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_send_sms.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_text_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_text_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_silent.xml b/core/res/res/drawable/ic_lockscreen_silent.xml
new file mode 100644
index 0000000..2521eb7
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_silent.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_silent_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_silent_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_soundon.xml b/core/res/res/drawable/ic_lockscreen_soundon.xml
new file mode 100644
index 0000000..2b306a5
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_soundon.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_soundon_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_soundon_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_unlock.xml b/core/res/res/drawable/ic_lockscreen_unlock.xml
new file mode 100644
index 0000000..0a49c18
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_unlock.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_unlock_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_lockscreen_unlock_activated" />
+
+</selector>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
index c9c1692..543747f 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
@@ -59,7 +59,7 @@
/>
<com.android.internal.widget.WaveView
- android:id="@+id/wave_view"
+ android:id="@+id/unlock_widget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
index 3bb7821..c83f910 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
@@ -50,7 +50,8 @@
android:layout_width="0dip"
android:gravity="center_horizontal|center_vertical">
- <TextView android:id="@+id/screenLocked"
+ <com.android.internal.widget.WaveView
+ android:id="@+id/unlock_widget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 5fe38d5..24891dc 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -22,11 +22,11 @@
depending on the state of the device. It is the same for landscape
and portrait.-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
- android:id="@+id/root">
+ android:id="@+id/root"
+ android:clipChildren="false">
<TextView
android:id="@+id/carrier"
@@ -162,13 +162,25 @@
android:drawablePadding="4dip"
/>
- <com.android.internal.widget.SlidingTab
- android:id="@+id/tab_selector"
+ <com.android.internal.widget.multiwaveview.MultiWaveView
+ android:id="@+id/unlock_widget"
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="300dip"
android:layout_alignParentBottom="true"
- android:layout_marginBottom="80dip"
+
+ android:targetDrawables="@array/lockscreen_targets_when_silent"
+ android:handleDrawable="@drawable/ic_lockscreen_handle"
+ android:waveDrawable="@drawable/ic_lockscreen_outerring"
+ android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius"
+ android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
+ android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
+ android:vibrationDuration="20"
+ android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
+ android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+ android:feedbackCount="3"
+ android:horizontalOffset="0dip"
+ android:verticalOffset="60dip"
/>
<!-- emergency call button shown when sim is PUKd and tab_selector is
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 3c2ad9a..02994a9 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -21,11 +21,11 @@
state of the device, as well as instructions on how to get past it
depending on the state of the device.-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
- android:id="@+id/root">
+ android:id="@+id/root"
+ android:clipChildren="false">
<!-- left side -->
<RelativeLayout
@@ -164,12 +164,23 @@
</RelativeLayout>
<!-- right side -->
- <com.android.internal.widget.SlidingTab
- android:id="@+id/tab_selector"
- android:orientation="vertical"
- android:layout_width="wrap_content"
+ <com.android.internal.widget.multiwaveview.MultiWaveView
+ android:id="@+id/unlock_widget"
+ android:layout_width="300dip"
android:layout_height="match_parent"
- android:layout_marginRight="80dip"
+
+ android:targetDrawables="@array/lockscreen_targets_when_silent"
+ android:handleDrawable="@drawable/ic_lockscreen_handle"
+ android:waveDrawable="@drawable/ic_lockscreen_outerring"
+ android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius"
+ android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
+ android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
+ android:vibrationDuration="20"
+ android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
+ android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+ android:feedbackCount="3"
+ android:horizontalOffset="60dip"
+ android:verticalOffset="0dip"
/>
<!-- emergency call button shown when sim is PUKd and tab_selector is
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
new file mode 100644
index 0000000..85130ba
--- /dev/null
+++ b/core/res/res/values-land/arrays.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Resources for MultiWaveView in LockScreen -->
+ <array name="ic_lockscreen_targets_when_silent">
+ <item>@null</item>"
+ <item>@drawable/ic_lockscreen_unlock</item>
+ <item>@null</item>
+ <item>@drawable/ic_lockscreen_soundon</item>
+ </array>
+
+ <array name="ic_lockscreen_targets_when_soundon">
+ <item>@null</item>"
+ <item>@drawable/ic_lockscreen_unlock</item>
+ <item>@null</item>
+ <item>@drawable/ic_lockscreen_silent</item>
+ </array>
+
+</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 810c3b2..0f04a67 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -333,4 +333,19 @@
<item>中文 (繁體)</item>
</string-array>
+ <!-- Resources for MultiWaveView in LockScreen -->
+ <array name="lockscreen_targets_when_silent">
+ <item>@drawable/ic_lockscreen_unlock</item>
+ <item>@null</item>
+ <item>@drawable/ic_lockscreen_soundon</item>
+ <item>@null</item>
+ </array>
+
+ <array name="lockscreen_targets_when_soundon">
+ <item>@drawable/ic_lockscreen_unlock</item>
+ <item>@null</item>
+ <item>@drawable/ic_lockscreen_silent</item>
+ <item>@null</item>"
+ </array>
+
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d5da592..acfdfc9 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5009,6 +5009,48 @@
</declare-styleable>
<!-- =============================== -->
+ <!-- MultiWaveView class attributes -->
+ <!-- =============================== -->
+ <eat-comment />
+ <declare-styleable name="MultiWaveView">
+ <!-- Reference to an array resource that be shown as targets around a circle. -->
+ <attr name="targetDrawables" format="reference"/>
+
+ <!-- Sets a drawable as the drag center. -->
+ <attr name="handleDrawable" format="reference" />
+
+ <!-- Drawable to use for chevron animation on the left. -->
+ <attr name="leftChevronDrawable" format="reference" />
+
+ <!-- Drawable to use for chevron animation on the right. -->
+ <attr name="rightChevronDrawable" format="reference" />
+
+ <!-- Drawable to use for wave ripple animation. -->
+ <attr name="waveDrawable" format="reference" />
+
+ <!-- Outer radius of target circle. Icons will be drawn on this circle. -->
+ <attr name="outerRadius" format="dimension" />
+
+ <!-- Size of target radius. Points within this distance of target center is a "hit". -->
+ <attr name="hitRadius" format="dimension" />
+
+ <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
+ <attr name="vibrationDuration" format="integer"/>
+
+ <!-- How close we need to be before snapping to a target. -->
+ <attr name="snapMargin" format="dimension" />
+
+ <!-- Number of waves/chevrons to show in animation. -->
+ <attr name="feedbackCount" format="integer" />
+
+ <!-- Used to shift center of pattern vertically. -->
+ <attr name="verticalOffset" format="dimension" />
+
+ <!-- Used to shift center of pattern horizontally. -->
+ <attr name="horizontalOffset" format="dimension" />
+ </declare-styleable>
+
+ <!-- =============================== -->
<!-- LockPatternView class attributes -->
<!-- =============================== -->
<eat-comment />
@@ -5145,7 +5187,7 @@
</declare-styleable>
<declare-styleable name="Storage">
- <!-- path to mount point for the storage -->
+ <!-- path to mount point for the storage -->
<attr name="mountPoint" format="string" />
<!-- user visible description of the storage -->
<attr name="storageDescription" format="string" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 724c528..df22f15 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -57,6 +57,15 @@
<!-- Default correction for the space key in the password keyboard -->
<dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
+ <!-- Default target placement radius for MultiWaveView -->
+ <dimen name="multiwaveview_target_placement_radius">135dip</dimen>
+
+ <!-- Default distance beyond which MultiWaveView snaps to the target radius -->
+ <dimen name="multiwaveview_snap_margin">20dip</dimen>
+
+ <!-- Default distance from each snap target that MultiWaveView considers a "hit" -->
+ <dimen name="multiwaveview_hit_radius">60dip</dimen>
+
<!-- Preference activity side margins -->
<dimen name="preference_screen_side_margin">0dp</dimen>
<!-- Preference activity side margins negative-->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 82a3b8a..4108c1b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1752,4 +1752,17 @@
<public type="attr" name="accessibilityFlags" />
<public type="attr" name="canRetrieveWindowContent" />
+ <public type="attr" name="targetDrawables" />
+ <public type="attr" name="handleDrawable" />
+ <public type="attr" name="leftChevronDrawable" />
+ <public type="attr" name="rightChevronDrawable" />
+ <public type="attr" name="waveDrawable" />
+ <public type="attr" name="outerRadius" />
+ <public type="attr" name="hitRadius" />
+ <public type="attr" name="vibrationDuration" />
+ <public type="attr" name="snapMargin" />
+ <public type="attr" name="feedbackCount" />
+ <public type="attr" name="verticalOffset" />
+ <public type="attr" name="horizontalOffset" />
+
</resources>
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 6f7a6ee..0178395 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -22,6 +22,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.SlidingTab;
import com.android.internal.widget.WaveView;
import com.android.internal.widget.WaveView.OnTriggerListener;
+import com.android.internal.widget.multiwaveview.MultiWaveView;
import android.app.ActivityManager;
import android.content.Context;
@@ -91,6 +92,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
private WaveView mEnergyWave;
private SlidingTabMethods mSlidingTabMethods;
private WaveViewMethods mWaveViewMethods;
+ private MultiWaveView mMultiWaveView;
+ private MultiWaveViewMethods mMultiWaveViewMethods;
/**
* The status of this lock screen.
@@ -166,34 +169,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) {
mCallback.goToUnlockScreen();
} else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
- // toggle silent mode
- mSilentMode = !mSilentMode;
- if (mSilentMode) {
- final boolean vibe = (Settings.System.getInt(
- getContext().getContentResolver(),
- Settings.System.VIBRATE_IN_SILENT, 1) == 1);
-
- mAudioManager.setRingerMode(vibe
- ? AudioManager.RINGER_MODE_VIBRATE
- : AudioManager.RINGER_MODE_SILENT);
- } else {
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- }
-
+ toggleRingMode();
updateRightTabResources();
-
- String message = mSilentMode ?
- getContext().getString(R.string.global_action_silent_mode_on_status) :
- getContext().getString(R.string.global_action_silent_mode_off_status);
-
- final int toastIcon = mSilentMode
- ? R.drawable.ic_lock_ringer_off
- : R.drawable.ic_lock_ringer_on;
-
- final int toastColor = mSilentMode
- ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff)
- : getContext().getResources().getColor(R.color.keyguard_text_color_soundon);
- toastMessage(mScreenLocked, message, toastColor, toastIcon);
+ doSilenceRingToast();
mCallback.pokeWakelock();
}
}
@@ -214,19 +192,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
}
}
- class WaveViewMethods implements WaveView.OnTriggerListener {
- private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
- private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
+ private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
+ private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
+ class WaveViewMethods implements WaveView.OnTriggerListener {
/** {@inheritDoc} */
public void onTrigger(View v, int whichHandle) {
if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) {
- // Delay hiding lock screen long enough for animation to finish
- postDelayed(new Runnable() {
- public void run() {
- mCallback.goToUnlockScreen();
- }
- }, WAIT_FOR_ANIMATION_TIMEOUT);
+ requestUnlockScreen();
}
}
@@ -243,6 +216,80 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
}
}
+ class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener {
+ public void onGrabbed(View v, int handle) {
+
+ }
+ public void onReleased(View v, int handle) {
+
+ }
+ public void onTrigger(View v, int target) {
+ if (target == 0) { // TODO: Use resources to determine which handle was used
+ mCallback.goToUnlockScreen();
+ } else if (target == 2) {
+ toggleRingMode();
+ updateResources();
+ doSilenceRingToast();
+ mCallback.pokeWakelock();
+ }
+
+ }
+
+ private void updateResources() {
+ mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
+ : R.array.lockscreen_targets_when_soundon);
+ }
+
+ public void onGrabbedStateChange(View v, int handle) {
+ // Don't poke the wake lock when returning to a state where the handle is
+ // not grabbed since that can happen when the system (instead of the user)
+ // cancels the grab.
+ if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) {
+ mCallback.pokeWakelock();
+ }
+ }
+ }
+
+ private void requestUnlockScreen() {
+ // Delay hiding lock screen long enough for animation to finish
+ postDelayed(new Runnable() {
+ public void run() {
+ mCallback.goToUnlockScreen();
+ }
+ }, WAIT_FOR_ANIMATION_TIMEOUT);
+ }
+
+ private void doSilenceRingToast() {
+ String message = mSilentMode ?
+ getContext().getString(R.string.global_action_silent_mode_on_status) :
+ getContext().getString(R.string.global_action_silent_mode_off_status);
+
+ final int toastIcon = mSilentMode
+ ? R.drawable.ic_lock_ringer_off
+ : R.drawable.ic_lock_ringer_on;
+
+ final int toastColor = mSilentMode
+ ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff)
+ : getContext().getResources().getColor(R.color.keyguard_text_color_soundon);
+ toastMessage(mScreenLocked, message, toastColor, toastIcon);
+ }
+
+ private void toggleRingMode() {
+ // toggle silent mode
+ mSilentMode = !mSilentMode;
+ if (mSilentMode) {
+ final boolean vibe = (Settings.System.getInt(
+ getContext().getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT, 1) == 1);
+
+ mAudioManager.setRingerMode(vibe
+ ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT);
+ } else {
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ }
+ }
+
/**
* In general, we enable unlocking the insecure key guard with the menu key. However, there are
* some cases where we wish to disable it, notably when the menu button placement or technology
@@ -319,9 +366,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = isSilentMode();
- mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector);
- mEnergyWave = (WaveView) findViewById(R.id.wave_view);
- if (mSlidingTab != null) {
+ View unlockWidget = findViewById(R.id.unlock_widget);
+ if (unlockWidget instanceof SlidingTab) {
+ mSlidingTab = (SlidingTab) unlockWidget;
mSlidingTab.setHoldAfterTrigger(true, false);
mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label);
mSlidingTab.setLeftTabResources(
@@ -332,11 +379,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mSlidingTabMethods = new SlidingTabMethods();
mSlidingTab.setOnTriggerListener(mSlidingTabMethods);
mSlidingTabMethods.updateRightTabResources();
- } else if (mEnergyWave != null) {
+ } else if (unlockWidget instanceof WaveView) {
+ mEnergyWave = (WaveView) unlockWidget;
mWaveViewMethods = new WaveViewMethods();
mEnergyWave.setOnTriggerListener(mWaveViewMethods);
+ } else if (unlockWidget instanceof MultiWaveView) {
+ mMultiWaveView = (MultiWaveView) unlockWidget;
+ mMultiWaveViewMethods = new MultiWaveViewMethods();
+ mMultiWaveViewMethods.updateResources(); // update silence/ring resources
+ mMultiWaveView.setOnTriggerListener(mMultiWaveViewMethods);
} else {
- throw new IllegalStateException("Must have either SlidingTab or WaveView defined");
+ throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget);
}
resetStatusInfo(updateMonitor);