summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java24
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java6
-rw-r--r--core/res/res/drawable-hdpi/kg_widget_delete_drop_target.pngbin0 -> 1003 bytes
-rw-r--r--core/res/res/drawable-mdpi/kg_widget_delete_drop_target.pngbin0 -> 802 bytes
-rw-r--r--core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.pngbin0 -> 1392 bytes
-rw-r--r--core/res/res/layout-land/keyguard_host_view.xml6
-rw-r--r--core/res/res/layout-land/keyguard_widget_pager.xml1
-rw-r--r--core/res/res/layout-port/keyguard_host_view.xml10
-rw-r--r--core/res/res/layout-port/keyguard_widget_pager.xml1
-rw-r--r--core/res/res/layout-sw600dp-port/keyguard_host_view.xml6
-rw-r--r--core/res/res/layout/keyguard_pin_view.xml2
-rw-r--r--core/res/res/layout/keyguard_sim_pin_view.xml254
-rw-r--r--core/res/res/layout/keyguard_sim_puk_view.xml256
-rw-r--r--core/res/res/layout/keyguard_widget_remove_drop_target.xml32
-rw-r--r--core/res/res/values-land/dimens.xml5
-rwxr-xr-xcore/res/res/values/config.xml6
-rw-r--r--core/res/res/values/dimens.xml5
-rwxr-xr-xcore/res/res/values/strings.xml12
-rw-r--r--core/res/res/values/styles.xml3
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java48
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java151
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java27
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java25
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java34
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java179
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java194
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java18
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java16
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java129
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java56
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java71
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java53
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java56
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java101
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/PagedView.java348
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java63
-rw-r--r--services/java/com/android/server/AppWidgetServiceImpl.java4
42 files changed, 1477 insertions, 758 deletions
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index d56556f..be6a770 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -244,14 +244,22 @@ public class AppWidgetHostView extends FrameLayout {
*
* @param newOptions The bundle of options, in addition to the size information,
* can be null.
- * @param minWidth The minimum width that the widget will be displayed at.
- * @param minHeight The maximum height that the widget will be displayed at.
- * @param maxWidth The maximum width that the widget will be displayed at.
- * @param maxHeight The maximum height that the widget will be displayed at.
+ * @param minWidth The minimum width in dips that the widget will be displayed at.
+ * @param minHeight The maximum height in dips that the widget will be displayed at.
+ * @param maxWidth The maximum width in dips that the widget will be displayed at.
+ * @param maxHeight The maximum height in dips that the widget will be displayed at.
*
*/
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
+ updateAppWidgetSize(newOptions, minWidth, minHeight, maxWidth, maxHeight, false);
+ }
+
+ /**
+ * @hide
+ */
+ public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
+ int maxHeight, boolean ignorePadding) {
if (newOptions == null) {
newOptions = new Bundle();
}
@@ -265,10 +273,10 @@ public class AppWidgetHostView extends FrameLayout {
int xPaddingDips = (int) ((padding.left + padding.right) / density);
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
- int newMinWidth = minWidth - xPaddingDips;
- int newMinHeight = minHeight - yPaddingDips;
- int newMaxWidth = maxWidth - xPaddingDips;
- int newMaxHeight = maxHeight - yPaddingDips;
+ int newMinWidth = minWidth - (ignorePadding ? 0 : xPaddingDips);
+ int newMinHeight = minHeight - (ignorePadding ? 0 : yPaddingDips);
+ int newMaxWidth = maxWidth - (ignorePadding ? 0 : xPaddingDips);
+ int newMaxHeight = maxHeight - (ignorePadding ? 0 : yPaddingDips);
AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3ee3c8c..e5e1a2b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1073,11 +1073,7 @@ public class LockPatternUtils {
}
return appWidgetIds;
}
- if (appWidgetIdString == null) {
- return new int[] { LockPatternUtils.ID_DEFAULT_STATUS_WIDGET };
- } else {
- return new int[0];
- }
+ return new int[0];
}
private static String combineStrings(int[] list, String separator) {
diff --git a/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..84549ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..219f3e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..d4965d9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index 67ac1d5..be1d5b6 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -33,6 +33,12 @@
android:layout_height="match_parent"
android:clipChildren="false">
+ <include layout="@layout/keyguard_widget_remove_drop_target"
+ android:id="@+id/keyguard_widget_pager_delete_target"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal" />
+
<include layout="@layout/keyguard_widget_pager"
android:id="@+id/app_widget_container"
android:layout_width="match_parent"
diff --git a/core/res/res/layout-land/keyguard_widget_pager.xml b/core/res/res/layout-land/keyguard_widget_pager.xml
index 975288f..02c6d0e 100644
--- a/core/res/res/layout-land/keyguard_widget_pager.xml
+++ b/core/res/res/layout-land/keyguard_widget_pager.xml
@@ -25,7 +25,6 @@
android:paddingRight="25dp"
android:paddingTop="25dp"
android:paddingBottom="25dp"
- android:clipChildren="false"
android:clipToPadding="false"
androidprv:pageSpacing="10dp">
</com.android.internal.policy.impl.keyguard.KeyguardWidgetCarousel> \ No newline at end of file
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index b3270e0..9921313 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -35,6 +35,16 @@
<FrameLayout
android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <include layout="@layout/keyguard_widget_remove_drop_target"
+ android:id="@+id/keyguard_widget_pager_delete_target"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_childType="widgets">
<include layout="@layout/keyguard_widget_pager"
diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml
index 7fd370b..7f22709 100644
--- a/core/res/res/layout-port/keyguard_widget_pager.xml
+++ b/core/res/res/layout-port/keyguard_widget_pager.xml
@@ -26,7 +26,6 @@
android:paddingRight="25dp"
android:paddingTop="25dp"
android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
- android:clipChildren="false"
android:clipToPadding="false"
androidprv:pageSpacing="10dp">
</com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
index 5d858ae..809104d 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -34,6 +34,12 @@
android:clipChildren="false"
android:orientation="vertical">
+ <include layout="@layout/keyguard_widget_remove_drop_target"
+ android:id="@+id/keyguard_widget_pager_delete_target"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal" />
+
<include layout="@layout/keyguard_widget_pager"
android:id="@+id/app_widget_container"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
index 29e69f3..d6cfe2a 100644
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ b/core/res/res/layout/keyguard_pin_view.xml
@@ -193,10 +193,10 @@
<ImageButton
android:id="@+id/key_enter"
style="@style/Widget.Button.NumPadKey"
- android:gravity="center"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:paddingRight="30dp"
android:src="@drawable/sym_keyboard_return_holo"
android:contentDescription="@string/keyboardview_keycode_enter"
/>
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
index ad61709..36e1b15 100644
--- a/core/res/res/layout/keyguard_sim_pin_view.xml
+++ b/core/res/res/layout/keyguard_sim_pin_view.xml
@@ -19,98 +19,200 @@
<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
<com.android.internal.policy.impl.keyguard.KeyguardSimPinView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_sim_pin_view"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_lockscreen_sim"/>
+
+ <include layout="@layout/keyguard_message_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:orientation="horizontal"
android:layout_weight="1"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_height="0dip"
- android:layout_width="match_parent"
+ >
+ <TextView android:id="@+id/pinEntry"
+ android:editable="true"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_lockscreen_sim"/>
-
- <include layout="@layout/keyguard_message_area_large"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <!-- Password entry field -->
- <!-- Note: the entire container is styled to look like the edit field,
- since the backspace/IME switcher looks better inside -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginEnd="4dip"
- android:layout_marginStart="4dip"
- android:gravity="center_vertical"
- android:background="#70000000">
-
- <!-- displays dots as user enters pin -->
- <EditText android:id="@+id/sim_pin_entry"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:maxLines="1"
- android:singleLine="true"
- android:gravity="center_horizontal"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
- android:textStyle="normal"
- android:inputType="textPassword"
- android:textSize="36sp"
- android:background="@null"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="#ffffffff"
- android:imeOptions="flagForceAscii|actionDone"
+ android:gravity="center"
+ android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+ android:singleLine="true"
+ android:cursorVisible="false"
+ android:background="@null"
+ android:textAppearance="@style/TextAppearance.NumPadKey"
+ android:imeOptions="flagForceAscii|actionDone"
/>
-
- <ImageButton android:id="@+id/delete_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:src="@android:drawable/ic_input_delete"
- android:clickable="true"
- android:padding="8dip"
- android:background="?android:attr/selectableItemBackground"
- />
- </LinearLayout>
-
- <!-- Numeric keyboard -->
- <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="4dip"
- android:layout_marginEnd="4dip"
- android:paddingTop="4dip"
- android:paddingBottom="4dip"
- android:background="#40000000"
- android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+ <ImageButton android:id="@+id/delete_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:src="@*android:drawable/ic_input_delete"
android:clickable="true"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@string/keyboardview_keycode_delete"
+ />
+ </LinearLayout>
+ <View
+ android:layout_width="wrap_content"
+ android:layout_height="1dp"
+ android:background="#55FFFFFF"
/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key1"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="1"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key2"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="2"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key3"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="3"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key4"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="4"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key5"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="5"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key6"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="6"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:orientation="horizontal"
+ android:layout_weight="1"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key7"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="7"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key8"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="8"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key9"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="9"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <Space
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key0"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="0"
+ />
+ <ImageButton
+ android:id="@+id/key_enter"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingRight="30dp"
+ android:src="@drawable/sym_keyboard_return_holo"
+ android:contentDescription="@string/keyboardview_keycode_enter"
+ />
</LinearLayout>
<include layout="@layout/keyguard_emergency_carrier_area"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal" />
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="bottom|center_horizontal"
+ android:gravity="center_horizontal" />
</com.android.internal.policy.impl.keyguard.KeyguardSimPinView>
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
index cc97005..e846a7b 100644
--- a/core/res/res/layout/keyguard_sim_puk_view.xml
+++ b/core/res/res/layout/keyguard_sim_puk_view.xml
@@ -20,97 +20,199 @@
carrier-provided PUK code and entering a new SIM PIN for it. -->
<com.android.internal.policy.impl.keyguard.KeyguardSimPukView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_sim_puk_view"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
android:gravity="center_horizontal">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_lockscreen_sim"/>
+
+ <include layout="@layout/keyguard_message_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:orientation="horizontal"
android:layout_weight="1"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_height="0dip"
- android:layout_width="match_parent"
+ >
+ <TextView android:id="@+id/pinEntry"
+ android:editable="true"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_lockscreen_sim"/>
-
- <include layout="@layout/keyguard_message_area_large"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <!-- Password entry field -->
- <!-- Note: the entire container is styled to look like the edit field,
- since the backspace/IME switcher looks better inside -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginEnd="4dip"
- android:layout_marginStart="4dip"
- android:gravity="center_vertical"
- android:background="#70000000">
-
- <!-- displays dots as user enters pin -->
- <EditText android:id="@+id/sim_pin_entry"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:maxLines="1"
- android:singleLine="true"
- android:gravity="center_horizontal"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
- android:textStyle="normal"
- android:inputType="textPassword"
- android:textSize="36sp"
- android:background="@null"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="#ffffffff"
- android:imeOptions="flagForceAscii|actionDone"
- />
-
- <ImageButton android:id="@+id/delete_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:src="@android:drawable/ic_input_delete"
- android:clickable="true"
- android:padding="8dip"
- android:background="?android:attr/selectableItemBackground"
+ android:gravity="center"
+ android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+ android:singleLine="true"
+ android:cursorVisible="false"
+ android:background="@null"
+ android:textAppearance="@style/TextAppearance.NumPadKey"
+ android:imeOptions="flagForceAscii|actionDone"
/>
- </LinearLayout>
-
- <!-- Numeric keyboard -->
- <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="4dip"
- android:layout_marginEnd="4dip"
- android:paddingTop="4dip"
- android:paddingBottom="4dip"
- android:background="#40000000"
- android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+ <ImageButton android:id="@+id/delete_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:src="@*android:drawable/ic_input_delete"
android:clickable="true"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@string/keyboardview_keycode_delete"
+ />
+ </LinearLayout>
+ <View
+ android:layout_width="wrap_content"
+ android:layout_height="1dp"
+ android:background="#55FFFFFF"
/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key1"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="1"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key2"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="2"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key3"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="3"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key4"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="4"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key5"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="5"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key6"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="6"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:orientation="horizontal"
+ android:layout_weight="1"
+ >
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key7"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="7"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key8"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="8"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key9"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="9"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ >
+ <Space
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ />
+ <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+ android:id="@+id/key0"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ androidprv:textView="@+id/pinEntry"
+ androidprv:digit="0"
+ />
+ <ImageButton
+ android:id="@+id/key_enter"
+ style="@style/Widget.Button.NumPadKey"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingRight="30dp"
+ android:src="@drawable/sym_keyboard_return_holo"
+ android:contentDescription="@string/keyboardview_keycode_enter"
+ />
</LinearLayout>
<include layout="@layout/keyguard_emergency_carrier_area"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal" />
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="bottom|center_horizontal"
+ android:gravity="center_horizontal" />
</com.android.internal.policy.impl.keyguard.KeyguardSimPukView>
diff --git a/core/res/res/layout/keyguard_widget_remove_drop_target.xml b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
new file mode 100644
index 0000000..c4fe9e0
--- /dev/null
+++ b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, 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.
+*/
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="center"
+ android:padding="20dp"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:drawableLeft="@drawable/kg_widget_delete_drop_target"
+ android:drawablePadding="4dp"
+ android:textColor="#FFF"
+ android:textSize="13sp"
+ android:shadowColor="#000"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+ android:visibility="gone" /> \ No newline at end of file
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 36f2628..8f1bd9a 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -56,4 +56,9 @@
<!-- Bottom padding for the widget pager -->
<dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+ <!-- If the height if keyguard drops below this threshold (most likely
+ due to the appearance of the IME), then drop the multiuser selector.
+ Landscape's layout allows this to be smaller than for portrait. -->
+ <dimen name="kg_squashed_layout_threshold">400dp</dimen>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 148560a..3b7d73a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -404,6 +404,12 @@
-->
<integer name="config_longPressOnPowerBehavior">1</integer>
+ <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
+ <string name="widget_default_package_name"></string>
+
+ <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
+ <string name="widget_default_class_name"></string>
+
<!-- Indicate whether the SD card is accessible without removing the battery. -->
<bool name="config_batterySdCardAccessibility">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4966b97..3a24cc1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -330,4 +330,9 @@
<!-- Size of the region along the edge of the screen that will accept
swipes to scroll the widget area. -->
<dimen name="kg_edge_swipe_region_size">24dp</dimen>
+
+ <!-- If the height if keyguard drops below this threshold (most likely
+ due to the appearance of the IME), then drop the multiuser selector. -->
+ <dimen name="kg_squashed_layout_threshold">600dp</dimen>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4495316..caa8f02 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2065,15 +2065,6 @@
<!-- This can be used in any application wanting to disable the text "Emergency number" -->
<string name="emergency_call_dialog_number_for_display">Emergency number</string>
- <!-- String to display if the clock status widget is selected (it is the default) [CHAR LIMIT=22] -->
- <string name="widget_default" msgid="8269383575996003796">Clock</string>
-
- <!-- Package name for default widget [DO NOT TRANSLATE] -->
- <string name="widget_default_package_name">com.android.deskclock</string>
-
- <!-- Class name for default widget [DO NOT TRANSLATE] -->
- <string name="widget_default_class_name">com.android.deskclock.DeskClock</string>
-
<!--
*** touch based lock / unlock ***
--> <skip />
@@ -3978,6 +3969,9 @@
you will be asked to unlock your phone using an email account.\n\n
Try again in <xliff:g id="number">%d</xliff:g> seconds.
</string>
+ <!-- Sequence of characters used to separate message strings in keyguard. Typically just em-dash
+ with spaces on either side. [CHAR LIMIT=3] -->
+ <string name="kg_text_message_separator" product="default"> \u2014 </string>
<!-- Message shown in dialog when user is attempting to set the music volume above the
recommended maximum level for headphones -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 180f864..f489786 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -2482,13 +2482,14 @@ please see styles_device_defaults.xml.
<style name="Widget.Button.NumPadKey"
parent="@android:style/Widget.Button">
<item name="android:singleLine">true</item>
- <item name="android:padding">6dip</item>
<item name="android:gravity">left|center_vertical</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:textSize">34dp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">#ffffff</item>
+ <item name="android:paddingBottom">10dp</item>
+ <item name="android:paddingLeft">20dp</item>
</style>
<style name="TextAppearance.NumPadKey"
parent="@android:style/TextAppearance">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 05edbcc..a12c14c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,7 +479,6 @@
<java-symbol type="string" name="emailTypeOther" />
<java-symbol type="string" name="emailTypeWork" />
<java-symbol type="string" name="emergency_call_dialog_number_for_display" />
- <java-symbol type="string" name="widget_default" />
<java-symbol type="string" name="widget_default_package_name" />
<java-symbol type="string" name="widget_default_class_name" />
<java-symbol type="string" name="emergency_calls_only" />
@@ -1235,6 +1234,7 @@
<java-symbol type="dimen" name="keyguard_avatar_frame_stroke_width" />
<java-symbol type="dimen" name="keyguard_avatar_frame_shadow_radius" />
<java-symbol type="dimen" name="kg_edge_swipe_region_size" />
+ <java-symbol type="dimen" name="kg_squashed_layout_threshold" />
<java-symbol type="drawable" name="ic_jog_dial_sound_off" />
<java-symbol type="drawable" name="ic_jog_dial_sound_on" />
<java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -1319,6 +1319,7 @@
<java-symbol type="id" name="keyguard_sim_puk_view" />
<java-symbol type="id" name="keyguard_account_view" />
<java-symbol type="id" name="keyguard_selector_fade_container" />
+ <java-symbol type="id" name="keyguard_widget_pager_delete_target" />
<java-symbol type="id" name="app_widget_container" />
<java-symbol type="id" name="view_flipper" />
<java-symbol type="id" name="emergency_call_button" />
@@ -1327,9 +1328,7 @@
<java-symbol type="id" name="lockPatternView" />
<java-symbol type="id" name="forgot_password_button" />
<java-symbol type="id" name="glow_pad_view" />
- <java-symbol type="id" name="sim_pin_entry" />
<java-symbol type="id" name="delete_button" />
- <java-symbol type="id" name="sim_pin_entry" />
<java-symbol type="id" name="keyguard_user_avatar" />
<java-symbol type="id" name="keyguard_user_name" />
<java-symbol type="id" name="keyguard_transport_control" />
@@ -1478,6 +1477,7 @@
<java-symbol type="string" name="kg_failed_attempts_almost_at_login" />
<java-symbol type="string" name="kg_enter_confirm_pin_hint" />
<java-symbol type="string" name="kg_invalid_confirm_pin_hint" />
+ <java-symbol type="string" name="kg_text_message_separator" />
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 983328d..5eeef93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -224,6 +224,8 @@ public class NavigationBarView extends LinearLayout {
(0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
? (mVertical ? mBackAltLandIcon : mBackAltIcon)
: (mVertical ? mBackLandIcon : mBackIcon));
+
+ setDisabledFlags(mDisabledFlags, true);
}
public void setDisabledFlags(int disabledFlags) {
@@ -237,7 +239,8 @@ public class NavigationBarView extends LinearLayout {
final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
- final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0);
+ final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
+ && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
if (SLIPPERY_WHEN_DISABLED) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
index 2728bfc..893df26 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -53,13 +53,14 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
private final Callbacks mCallbacks;
private final WindowManager mWindowManager;
private final Point mRenderedSize = new Point();
+ private final int[] mScreenLocation = new int[2];
private View mWidgetView;
private long mLaunchCameraStart;
private boolean mActive;
- private boolean mChallengeActive;
private boolean mTransitioning;
private boolean mDown;
+ private boolean mWindowFocused;
private final Runnable mLaunchCameraRunnable = new Runnable() {
@Override
@@ -186,7 +187,7 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
}
private void transitionToCamera() {
- if (mTransitioning || mChallengeActive || mDown) return;
+ if (mTransitioning || mDown) return;
mTransitioning = true;
@@ -233,7 +234,7 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
public void onClick(View v) {
if (DEBUG) Log.d(TAG, "clicked");
if (mTransitioning) return;
- if (mActive && !mChallengeActive) {
+ if (mActive) {
cancelTransitionToCamera();
transitionToCamera();
}
@@ -242,6 +243,7 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
+ mWindowFocused = hasWindowFocus;
if (DEBUG) Log.d(TAG, "onWindowFocusChanged: " + hasWindowFocus);
if (!hasWindowFocus) {
mTransitioning = false;
@@ -265,13 +267,29 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
}
@Override
- public boolean onUserInteraction(int action) {
- if (mTransitioning) return true;
- if (DEBUG) Log.d(TAG, "onUserInteraction " + action);
+ public boolean onUserInteraction(MotionEvent event) {
+ if (!mWindowFocused) {
+ if (DEBUG) Log.d(TAG, "onUserInteraction eaten: !mWindowFocused");
+ return true;
+ }
+ if (mTransitioning) {
+ if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
+ return true;
+ }
+
+ getLocationOnScreen(mScreenLocation);
+ int rawBottom = mScreenLocation[1] + getHeight();
+ if (event.getRawY() > rawBottom) {
+ if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
+ return true;
+ }
+
+ int action = event.getAction();
mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
- if (mActive && !mChallengeActive) {
+ if (mActive) {
rescheduleTransitionToCamera();
}
+ if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
return false;
}
@@ -282,20 +300,6 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
super.onFocusLost();
}
- @Override
- public void onChallengeActive(boolean challengeActive) {
- if (DEBUG) Log.d(TAG, "onChallengeActive: " + challengeActive);
- mChallengeActive = challengeActive;
- if (mTransitioning) return;
- if (mActive) {
- if (mChallengeActive) {
- cancelTransitionToCamera();
- } else {
- rescheduleTransitionToCamera();
- }
- }
- }
-
public void onScreenTurnedOff() {
if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
reset();
@@ -321,7 +325,6 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
if (DEBUG) Log.d(TAG, "reset");
mLaunchCameraStart = 0;
mTransitioning = false;
- mChallengeActive = false;
mDown = false;
cancelTransitionToCamera();
animate().cancel();
@@ -347,6 +350,7 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
if (newWindowAnimations != wlp.windowAnimations) {
+ if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations);
wlp.windowAnimations = newWindowAnimations;
mWindowManager.updateViewLayout(root, wlp);
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
index b031baf..f3ea992 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
@@ -27,6 +27,8 @@ import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.widget.LockPatternUtils;
public class CarrierText extends TextView {
+ private static CharSequence mSeparator;
+
private LockPatternUtils mLockPatternUtils;
private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@@ -82,6 +84,7 @@ public class CarrierText extends TextView {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mSeparator = getResources().getString(R.string.kg_text_message_separator);
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
setSelected(true); // Allow marquee to work.
}
@@ -202,7 +205,7 @@ public class CarrierText extends TextView {
final boolean plmnValid = !TextUtils.isEmpty(plmn);
final boolean spnValid = !TextUtils.isEmpty(spn);
if (plmnValid && spnValid) {
- return plmn + "|" + spn;
+ return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
} else if (plmnValid) {
return plmn;
} else if (spnValid) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
index db36bcc..71526d2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
@@ -130,6 +130,15 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
}
+ /*
+ * Override this if you have a different string for "wrong password"
+ *
+ * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
+ */
+ protected int getWrongPasswordStringId() {
+ return R.string.kg_wrong_password;
+ }
+
protected void verifyPasswordAndUnlock() {
String entry = mPasswordEntry.getText().toString();
if (mLockPatternUtils.checkPassword(entry)) {
@@ -144,7 +153,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
handleAttemptLockout(deadline);
}
- mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pin, true);
+ mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
}
mPasswordEntry.setText("");
}
@@ -164,6 +173,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
@Override
public void onFinish() {
+ mSecurityMessageDisplay.setMessage("", false);
resetState();
}
}.start();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index ca3d0a2..d286564 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -29,8 +29,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -50,7 +48,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.widget.RemoteViews.OnClickHandler;
@@ -59,7 +56,6 @@ import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityM
import com.android.internal.widget.LockPatternUtils;
import java.io.File;
-import java.util.ArrayList;
import java.util.List;
public class KeyguardHostView extends KeyguardViewBase {
@@ -68,10 +64,10 @@ public class KeyguardHostView extends KeyguardViewBase {
// Use this to debug all of keyguard
public static boolean DEBUG = KeyguardViewMediator.DEBUG;
- // also referenced in SecuritySettings.java
static final int APPWIDGET_HOST_ID = 0x4B455947;
private AppWidgetHost mAppWidgetHost;
+ private AppWidgetManager mAppWidgetManager;
private KeyguardWidgetPager mAppWidgetContainer;
private KeyguardSecurityViewFlipper mSecurityViewContainer;
private KeyguardSelectorView mKeyguardSelectorView;
@@ -113,6 +109,7 @@ public class KeyguardHostView extends KeyguardViewBase {
mLockPatternUtils = new LockPatternUtils(context);
mAppWidgetHost = new AppWidgetHost(
context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
+ mAppWidgetManager = AppWidgetManager.getInstance(mContext);
mSecurityModel = new KeyguardSecurityModel(context);
// The following enables the MENU key to work for testing automation
@@ -153,15 +150,13 @@ public class KeyguardHostView extends KeyguardViewBase {
protected void onFinishInflate() {
// Grab instances of and make any necessary changes to the main layouts. Create
// view state manager and wire up necessary listeners / callbacks.
+ View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
mAppWidgetContainer.setVisibility(VISIBLE);
mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
+ mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
mAppWidgetContainer.setMinScale(0.5f);
- addDefaultWidgets();
- addWidgetsFromSettings();
- mSwitchPageRunnable.run();
-
SlidingChallengeLayout slider =
(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
if (slider != null) {
@@ -183,8 +178,11 @@ public class KeyguardHostView extends KeyguardViewBase {
setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
}
- showPrimarySecurityScreen(false);
+ addDefaultWidgets();
+ addWidgetsFromSettings();
+ mSwitchPageRunnable.run();
+ showPrimarySecurityScreen(false);
updateSecurityViews();
}
@@ -549,8 +547,6 @@ public class KeyguardHostView extends KeyguardViewBase {
};
};
- private KeyguardStatusViewManager mKeyguardStatusViewManager;
-
// Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
// This avoids unwanted asynchronous events from messing with the state.
private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
@@ -590,6 +586,8 @@ public class KeyguardHostView extends KeyguardViewBase {
}
};
+ protected boolean mShowSecurityWhenReturn;
+
@Override
public void reset() {
mIsVerifyUnlockOnly = false;
@@ -715,6 +713,7 @@ public class KeyguardHostView extends KeyguardViewBase {
// biometric unlock to start next time keyguard is shown.
KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
saveStickyWidgetIndex();
+ checkAppWidgetConsistency();
showPrimarySecurityScreen(true);
getSecurityView(mCurrentSecuritySelection).onPause();
CameraWidgetFrame cameraPage = findCameraPage();
@@ -812,15 +811,16 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
- private void addWidget(int appId, int pageIndex) {
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
- AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
+ private boolean addWidget(int appId, int pageIndex) {
+ AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
if (appWidgetInfo != null) {
AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
addWidget(view, pageIndex);
+ return true;
} else {
Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
mLockPatternUtils.removeAppWidget(appId);
+ return false;
}
}
@@ -842,11 +842,11 @@ public class KeyguardHostView extends KeyguardViewBase {
SlidingChallengeLayout slider = locateSlider();
if (slider != null) {
slider.setHandleAlpha(1);
- slider.showChallenge(true);
}
+ mShowSecurityWhenReturn = true;
}
- private SlidingChallengeLayout locateSlider() {
+ public SlidingChallengeLayout locateSlider() {
return (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
}
};
@@ -890,22 +890,7 @@ public class KeyguardHostView extends KeyguardViewBase {
@Override
public void run() {
- int defaultIconId = 0;
- Resources res = KeyguardHostView.this.getContext().getResources();
- ComponentName clock = new ComponentName(
- res.getString(R.string.widget_default_package_name),
- res.getString(R.string.widget_default_class_name));
- try {
- ActivityInfo activityInfo =
- mContext.getPackageManager().getActivityInfo(clock, 0);
- if (activityInfo != null) {
- defaultIconId = activityInfo.icon;
- }
- } catch (PackageManager.NameNotFoundException e) {
- defaultIconId = 0;
- }
- launchPickActivityIntent(R.string.widget_default, defaultIconId, clock,
- LockPatternUtils.EXTRA_DEFAULT_WIDGET);
+ launchPickActivityIntent();
}
});
mCallback.dismiss(false);
@@ -916,8 +901,7 @@ public class KeyguardHostView extends KeyguardViewBase {
initializeTransportControl();
}
- private void launchPickActivityIntent(int defaultLabelId, int defaultIconId,
- ComponentName defaultComponentName, String defaultTag) {
+ private void launchPickActivityIntent() {
// Create intent to pick widget
Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
@@ -928,22 +912,6 @@ public class KeyguardHostView extends KeyguardViewBase {
pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
- // Add an custom entry for the default
- AppWidgetProviderInfo defaultInfo = new AppWidgetProviderInfo();
- ArrayList<AppWidgetProviderInfo> extraInfos = new ArrayList<AppWidgetProviderInfo>();
- defaultInfo.label = getResources().getString(defaultLabelId);
- defaultInfo.icon = defaultIconId;
- defaultInfo.provider = defaultComponentName;
- extraInfos.add(defaultInfo);
-
- ArrayList<Bundle> extraExtras = new ArrayList<Bundle>();
- Bundle b = new Bundle();
- b.putBoolean(defaultTag, true);
- extraExtras.add(b);
-
- // Launch the widget picker
- pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, extraInfos);
- pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, extraExtras);
pickIntent.putExtra(Intent.EXTRA_INTENT, getBaseIntent());
pickIntent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
@@ -1024,6 +992,22 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
+ private int getAddPageIndex() {
+ View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
+ int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
+ // This shouldn't happen, but just to be safe!
+ if (addPageIndex < 0) {
+ addPageIndex = 0;
+ }
+ return addPageIndex;
+ }
+
+ private void addDefaultStatusWidget(int index) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
+ mAppWidgetContainer.addWidget(statusWidget, index);
+ }
+
private void addWidgetsFromSettings() {
DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -1036,23 +1020,17 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
- View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
- int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
- // This shouldn't happen, but just to be safe!
- if (addPageIndex < 0) {
- addPageIndex = 0;
- }
+ int addPageIndex = getAddPageIndex();
// Add user-selected widget
final int[] widgets = mLockPatternUtils.getAppWidgets();
+
if (widgets == null) {
Log.d(TAG, "Problem reading widgets");
} else {
for (int i = widgets.length -1; i >= 0; i--) {
if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
- mAppWidgetContainer.addWidget(statusWidget, addPageIndex + 1);
+ addDefaultStatusWidget(addPageIndex + 1);
} else {
// We add the widgets from left to right, starting after the first page after
// the add page. We count down, since the order will be persisted from right
@@ -1061,6 +1039,42 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
}
+ checkAppWidgetConsistency();
+ }
+
+ public void checkAppWidgetConsistency() {
+ final int childCount = mAppWidgetContainer.getChildCount();
+ boolean widgetPageExists = false;
+ for (int i = 0; i < childCount; i++) {
+ if (isWidgetPage(i)) {
+ widgetPageExists = true;
+ break;
+ }
+ }
+ if (!widgetPageExists) {
+ final int addPageIndex = getAddPageIndex();
+
+ Resources res = getContext().getResources();
+ ComponentName defaultAppWidget = new ComponentName(
+ res.getString(R.string.widget_default_package_name),
+ res.getString(R.string.widget_default_class_name));
+
+ // Note: we don't support configuring the widget
+ int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+ boolean bindSuccessful = false;
+ try {
+ mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
+ bindSuccessful = true;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
+ }
+ // Use the built-in status/clock view if we can't inflate the default widget
+ if (!(bindSuccessful && addWidget(appWidgetId, addPageIndex + 1))) {
+ addDefaultStatusWidget(addPageIndex + 1);
+ }
+ mAppWidgetContainer.onAddView(
+ mAppWidgetContainer.getChildAt(addPageIndex + 1), addPageIndex + 1);
+ }
}
Runnable mSwitchPageRunnable = new Runnable() {
@@ -1129,6 +1143,14 @@ public class KeyguardHostView extends KeyguardViewBase {
if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
if (!hasWindowFocus) {
saveStickyWidgetIndex();
+ } else if (mShowSecurityWhenReturn) {
+ SlidingChallengeLayout slider =
+ (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+ if (slider != null) {
+ slider.setHandleAlpha(1);
+ slider.showChallenge(true);
+ }
+ mShowSecurityWhenReturn = false;
}
}
@@ -1155,6 +1177,15 @@ public class KeyguardHostView extends KeyguardViewBase {
return null;
}
+ private boolean isWidgetPage(int pageIndex) {
+ View v = mAppWidgetContainer.getChildAt(pageIndex);
+ if (v != null && v instanceof KeyguardWidgetFrame) {
+ KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
+ return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
+ return false;
+ }
+
private boolean isCameraPage(int pageIndex) {
View v = mAppWidgetContainer.getChildAt(pageIndex);
return v != null && v instanceof CameraWidgetFrame;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index 5e331e1..f6f3fab 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -43,7 +43,6 @@ class KeyguardMessageArea extends TextView {
static final int SECURITY_MESSAGE_DURATION = 5000;
protected static final int FADE_DURATION = 750;
- static final String SEPARATOR = " ";
// are we showing battery information?
boolean mShowingBatteryInfo = false;
@@ -143,6 +142,8 @@ class KeyguardMessageArea extends TextView {
}
};
+ private CharSequence mSeparator;
+
public KeyguardMessageArea(Context context) {
this(context, null);
}
@@ -158,6 +159,8 @@ class KeyguardMessageArea extends TextView {
mUpdateMonitor.registerCallback(mInfoCallback);
mHandler = new Handler(Looper.myLooper());
+ mSeparator = getResources().getString(R.string.kg_text_message_separator);
+
update();
}
@@ -186,23 +189,23 @@ class KeyguardMessageArea extends TextView {
setText(status);
}
-
- private CharSequence concat(Object... args) {
+ private CharSequence concat(CharSequence... args) {
StringBuilder b = new StringBuilder();
- for (int i = 0; i < args.length; i++) {
- final Object arg = args[i];
- if (arg instanceof CharSequence) {
- b.append((CharSequence)args[i]);
- b.append(SEPARATOR);
- } else if (arg instanceof String) {
- b.append((String)args[i]);
- b.append(SEPARATOR);
+ if (!TextUtils.isEmpty(args[0])) {
+ b.append(args[0]);
+ }
+ for (int i = 1; i < args.length; i++) {
+ CharSequence text = args[i];
+ if (!TextUtils.isEmpty(text)) {
+ if (b.length() > 0) {
+ b.append(mSeparator);
+ }
+ b.append(text);
}
}
return b.toString();
}
-
CharSequence getCurrentMessage() {
return mShowingMessage ? mMessage : null;
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
index b7d9990..fa80352 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
@@ -65,10 +65,12 @@ public class KeyguardPINView extends KeyguardAbsKeyInputView
@Override
public void onClick(View v) {
doHapticKeyClick();
- verifyPasswordAndUnlock();
+ if (mPasswordEntry.isEnabled()) {
+ verifyPasswordAndUnlock();
+ }
}
});
- ok.setOnHoverListener(new NumPadKey.LiftToActivateListener(getContext()));
+ ok.setOnHoverListener(new LiftToActivateListener(getContext()));
}
// The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
@@ -78,16 +80,22 @@ public class KeyguardPINView extends KeyguardAbsKeyInputView
pinDelete.setVisibility(View.VISIBLE);
pinDelete.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
- CharSequence str = mPasswordEntry.getText();
- if (str.length() > 0) {
- mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ CharSequence str = mPasswordEntry.getText();
+ if (str.length() > 0) {
+ mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+ }
}
doHapticKeyClick();
}
});
pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
- mPasswordEntry.setText("");
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ mPasswordEntry.setText("");
+ }
doHapticKeyClick();
return true;
}
@@ -104,4 +112,9 @@ public class KeyguardPINView extends KeyguardAbsKeyInputView
@Override
public void showUsabilityHint() {
}
+
+ @Override
+ public int getWrongPasswordStringId() {
+ return R.string.kg_wrong_pin;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index 64bbdd3..23ea2e9 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -195,4 +195,9 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
@Override
public void showUsabilityHint() {
}
+
+ @Override
+ public int getWrongPasswordStringId() {
+ return R.string.kg_wrong_password;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
index 04ab0a2..7b11507 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
@@ -1,11 +1,13 @@
package com.android.internal.policy.impl.keyguard;
import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.FrameLayout;
import com.android.internal.R;
@@ -51,18 +53,42 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
public void showBouncer(int duration) {
- SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+ SecurityMessageDisplay message = new KeyguardMessageArea.Helper(getSecurityView());
message.showBouncer(duration);
- Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 1f);
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(ObjectAnimator.ofFloat(this, "backgroundAlpha", 1f), getEcaAnim(0f));
anim.setDuration(duration);
anim.start();
}
public void hideBouncer(int duration) {
- SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+ SecurityMessageDisplay message = new KeyguardMessageArea.Helper(getSecurityView());
message.hideBouncer(duration);
- Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 0f);
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(ObjectAnimator.ofFloat(this, "backgroundAlpha", 0f), getEcaAnim(1f));
anim.setDuration(duration);
anim.start();
}
+
+ View getSecurityView() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof KeyguardSecurityViewFlipper) {
+ return (View) (((KeyguardSecurityViewFlipper) child).getSecurityView());
+ }
+ }
+ return null;
+ }
+
+ Animator getEcaAnim(float alpha) {
+ Animator anim = null;
+ View securityView = getSecurityView();
+ if (securityView != null) {
+ View ecaView = securityView.findViewById(R.id.keyguard_selector_fade_container);
+ if (ecaView != null) {
+ anim = ObjectAnimator.ofFloat(ecaView, "alpha", alpha);
+ }
+ }
+ return anim;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
index fcf45ff..ab364ee 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
@@ -16,47 +16,32 @@
package com.android.internal.policy.impl.keyguard;
+import com.android.internal.telephony.ITelephony;
+
+import android.content.Context;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
-import android.content.Context;
-import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
-
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
-import com.android.internal.R;
-
import android.text.Editable;
+import android.text.InputType;
import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
+import com.android.internal.R;
+
/**
- * Displays a dialer like interface to unlock the SIM PIN.
+ * Displays a PIN pad for unlocking.
*/
-public class KeyguardSimPinView extends LinearLayout
+public class KeyguardSimPinView extends KeyguardAbsKeyInputView
implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
- private EditText mPinEntry;
private ProgressDialog mSimUnlockProgressDialog = null;
- private KeyguardSecurityCallback mCallback;
- private PasswordEntryKeyboardView mKeyboardView;
- private PasswordEntryKeyboardHelper mKeyboardHelper;
- private LockPatternUtils mLockPatternUtils;
- private SecurityMessageDisplay mSecurityMessageDisplay;
-
private volatile boolean mSimCheckInProgress;
public KeyguardSimPinView(Context context) {
@@ -65,68 +50,69 @@ public class KeyguardSimPinView extends LinearLayout
public KeyguardSimPinView(Context context, AttributeSet attrs) {
super(context, attrs);
- mLockPatternUtils = new LockPatternUtils(getContext());
}
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- mCallback = callback;
+ public void resetState() {
+ mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
+ mPasswordEntry.setEnabled(true);
+ }
+
+ @Override
+ protected int getPasswordTextViewId() {
+ return R.id.pinEntry;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mPinEntry = (EditText) findViewById(R.id.sim_pin_entry);
- mPinEntry.setOnEditorActionListener(this);
- mPinEntry.addTextChangedListener(this);
-
- mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
- mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
- new int[] {
- R.xml.kg_password_kbd_numeric,
- com.android.internal.R.xml.password_kbd_qwerty,
- com.android.internal.R.xml.password_kbd_qwerty_shifted,
- com.android.internal.R.xml.password_kbd_symbols,
- com.android.internal.R.xml.password_kbd_symbols_shift
- });
- mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
- mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
-
- final View deleteButton = findViewById(R.id.delete_button);
- if (deleteButton != null) {
- deleteButton.setOnClickListener(new OnClickListener() {
+ final View ok = findViewById(R.id.key_enter);
+ if (ok != null) {
+ ok.setOnClickListener(new View.OnClickListener() {
+ @Override
public void onClick(View v) {
- mKeyboardHelper.handleBackspace();
+ doHapticKeyClick();
+ verifyPasswordAndUnlock();
}
});
}
- mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
- mSecurityMessageDisplay.setTimeout(0);
- reset();
- }
-
- @Override
- protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- return mPinEntry.requestFocus(direction, previouslyFocusedRect);
- }
+ // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+ // not a separate view
+ View pinDelete = findViewById(R.id.delete_button);
+ if (pinDelete != null) {
+ pinDelete.setVisibility(View.VISIBLE);
+ pinDelete.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ CharSequence str = mPasswordEntry.getText();
+ if (str.length() > 0) {
+ mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+ }
+ doHapticKeyClick();
+ }
+ });
+ pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ mPasswordEntry.setText("");
+ doHapticKeyClick();
+ return true;
+ }
+ });
+ }
- public void reset() {
- // start fresh
- mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
+ mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
- // make sure that the number of entered digits is consistent when we
- // erase the SIM unlock code, including orientation changes.
- mPinEntry.setText("");
- mPinEntry.requestFocus();
+ mPasswordEntry.requestFocus();
}
@Override
public void showUsabilityHint() {
}
- /** {@inheritDoc} */
- public void cleanUp() {
+ @Override
+ public void onPause() {
// dismiss the dialog.
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.dismiss();
@@ -167,19 +153,6 @@ public class KeyguardSimPinView extends LinearLayout
}
}
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- // Check if this was the result of hitting the enter key
- mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
- if (event.getAction() == MotionEvent.ACTION_DOWN && (
- actionId == EditorInfo.IME_NULL
- || actionId == EditorInfo.IME_ACTION_DONE
- || actionId == EditorInfo.IME_ACTION_NEXT)) {
- checkPin();
- return true;
- }
- return false;
- }
-
private Dialog getSimUnlockProgressDialog() {
if (mSimUnlockProgressDialog == null) {
mSimUnlockProgressDialog = new ProgressDialog(mContext);
@@ -195,11 +168,14 @@ public class KeyguardSimPinView extends LinearLayout
return mSimUnlockProgressDialog;
}
- private void checkPin() {
- if (mPinEntry.getText().length() < 4) {
+ @Override
+ protected void verifyPasswordAndUnlock() {
+ String entry = mPasswordEntry.getText().toString();
+
+ if (entry.length() < 4) {
// otherwise, display a message to the user, and don't submit.
mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true);
- mPinEntry.setText("");
+ mPasswordEntry.setText("");
mCallback.userActivity(0);
return;
}
@@ -208,7 +184,7 @@ public class KeyguardSimPinView extends LinearLayout
if (!mSimCheckInProgress) {
mSimCheckInProgress = true; // there should be only one
- new CheckSimPin(mPinEntry.getText().toString()) {
+ new CheckSimPin(mPasswordEntry.getText().toString()) {
void onSimCheckResponse(final boolean success) {
post(new Runnable() {
public void run() {
@@ -223,7 +199,7 @@ public class KeyguardSimPinView extends LinearLayout
} else {
mSecurityMessageDisplay.setMessage
(R.string.kg_password_wrong_pin_code, true);
- mPinEntry.setText("");
+ mPasswordEntry.setText("");
}
mCallback.userActivity(0);
mSimCheckInProgress = false;
@@ -233,40 +209,5 @@ public class KeyguardSimPinView extends LinearLayout
}.start();
}
}
-
- public void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
- }
-
- public boolean needsInput() {
- return false; // This view provides its own keypad
- }
-
- public void onPause() {
-
- }
-
- public void onResume() {
- reset();
- }
-
- public KeyguardSecurityCallback getCallback() {
- return mCallback;
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- if (mCallback != null) {
- mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
- }
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
-
}
+
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
index 0465805..e5b4b73 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
@@ -19,49 +19,30 @@ import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
-import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.Editable;
+import android.text.InputType;
import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.android.internal.telephony.ITelephony;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
-import com.android.internal.R;
-public class KeyguardSimPukView extends LinearLayout implements View.OnClickListener,
- KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+import com.android.internal.R;
- private View mDeleteButton;
+/**
+ * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
+ */
+public class KeyguardSimPukView extends KeyguardAbsKeyInputView
+ implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
private ProgressDialog mSimUnlockProgressDialog = null;
- private KeyguardSecurityCallback mCallback;
-
- private SecurityMessageDisplay mSecurityMessageDisplay;
-
- private PasswordEntryKeyboardView mKeyboardView;
-
- private PasswordEntryKeyboardHelper mKeyboardHelper;
-
- private LockPatternUtils mLockPatternUtils;
-
private volatile boolean mCheckInProgress;
-
- private TextView mSimPinEntry;
-
private String mPukText;
-
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
@@ -95,10 +76,11 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message;
updateSim();
} else {
+ state = ENTER_PIN; // try again?
msg = R.string.kg_invalid_confirm_pin_hint;
}
}
- mSimPinEntry.setText(null);
+ mPasswordEntry.setText(null);
if (msg != 0) {
mSecurityMessageDisplay.setMessage(msg, true);
}
@@ -109,7 +91,7 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
mPukText="";
state = ENTER_PUK;
mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true);
- mSimPinEntry.requestFocus();
+ mPasswordEntry.requestFocus();
}
}
@@ -119,62 +101,71 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
public KeyguardSimPukView(Context context, AttributeSet attrs) {
super(context, attrs);
- mLockPatternUtils = new LockPatternUtils(getContext());
}
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- mCallback = callback;
- mLockPatternUtils = new LockPatternUtils(getContext());
+ public void resetState() {
+ mStateMachine.reset();
+ mPasswordEntry.setEnabled(true);
}
@Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mSimPinEntry = (TextView) findViewById(R.id.sim_pin_entry);
- mSimPinEntry.setOnEditorActionListener(this);
- mSimPinEntry.addTextChangedListener(this);
- mDeleteButton = findViewById(R.id.delete_button);
- mDeleteButton.setOnClickListener(this);
- mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
- mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
- new int[] {
- R.xml.kg_password_kbd_numeric,
- com.android.internal.R.xml.password_kbd_qwerty,
- com.android.internal.R.xml.password_kbd_qwerty_shifted,
- com.android.internal.R.xml.password_kbd_symbols,
- com.android.internal.R.xml.password_kbd_symbols_shift
- });
- mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
- mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
-
- mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
- mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
- reset();
+ protected int getPasswordTextViewId() {
+ return R.id.pinEntry;
}
@Override
- protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- return mSimPinEntry.requestFocus(direction, previouslyFocusedRect);
- }
+ protected void onFinishInflate() {
+ super.onFinishInflate();
- public boolean needsInput() {
- return false; // This view provides its own keypad
- }
+ final View ok = findViewById(R.id.key_enter);
+ if (ok != null) {
+ ok.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doHapticKeyClick();
+ verifyPasswordAndUnlock();
+ }
+ });
+ }
- public void onPause() {
+ // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+ // not a separate view
+ View pinDelete = findViewById(R.id.delete_button);
+ if (pinDelete != null) {
+ pinDelete.setVisibility(View.VISIBLE);
+ pinDelete.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ CharSequence str = mPasswordEntry.getText();
+ if (str.length() > 0) {
+ mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+ }
+ doHapticKeyClick();
+ }
+ });
+ pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ mPasswordEntry.setText("");
+ doHapticKeyClick();
+ return true;
+ }
+ });
+ }
- }
+ mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+
+ mPasswordEntry.requestFocus();
- public void onResume() {
- reset();
+ mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
}
@Override
public void showUsabilityHint() {
}
- /** {@inheritDoc} */
- public void cleanUp() {
+ @Override
+ public void onPause() {
// dismiss the dialog.
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.dismiss();
@@ -218,23 +209,11 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
}
}
- public void onClick(View v) {
- if (v == mDeleteButton) {
- mSimPinEntry.requestFocus();
- final Editable digits = mSimPinEntry.getEditableText();
- final int len = digits.length();
- if (len > 0) {
- digits.delete(len-1, len);
- }
- }
- mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
- }
-
private Dialog getSimUnlockProgressDialog() {
if (mSimUnlockProgressDialog == null) {
mSimUnlockProgressDialog = new ProgressDialog(mContext);
- mSimUnlockProgressDialog.setMessage(mContext.getString(
- R.string.kg_sim_unlock_progress_dialog_message));
+ mSimUnlockProgressDialog.setMessage(
+ mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
mSimUnlockProgressDialog.setIndeterminate(true);
mSimUnlockProgressDialog.setCancelable(false);
if (!(mContext instanceof Activity)) {
@@ -247,8 +226,8 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
private boolean checkPuk() {
// make sure the puk is at least 8 digits long.
- if (mSimPinEntry.getText().length() >= 8) {
- mPukText = mSimPinEntry.getText().toString();
+ if (mPasswordEntry.getText().length() >= 8) {
+ mPukText = mPasswordEntry.getText().toString();
return true;
}
return false;
@@ -256,16 +235,16 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
private boolean checkPin() {
// make sure the PIN is between 4 and 8 digits
- int length = mSimPinEntry.getText().length();
+ int length = mPasswordEntry.getText().length();
if (length >= 4 && length <= 8) {
- mPinText = mSimPinEntry.getText().toString();
+ mPinText = mPasswordEntry.getText().toString();
return true;
}
return false;
}
public boolean confirmPin() {
- return mPinText.equals(mSimPinEntry.getText().toString());
+ return mPinText.equals(mPasswordEntry.getText().toString());
}
private void updateSim() {
@@ -295,46 +274,9 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
}
@Override
- public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
- // Check if this was the result of hitting the enter key
- mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
- || actionId == EditorInfo.IME_ACTION_NEXT) {
- mStateMachine.next();
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
- }
-
- @Override
- public void reset() {
- mStateMachine.reset();
- }
-
- @Override
- public KeyguardSecurityCallback getCallback() {
- return mCallback;
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- if (mCallback != null) {
- mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
- }
+ protected void verifyPasswordAndUnlock() {
+ mStateMachine.next();
}
+}
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- @Override
- public void afterTextChanged(Editable s) {
- }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index fe4ac5b..d0fa81e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -520,8 +520,22 @@ public class KeyguardViewMediator {
mSystemReady = true;
mUpdateMonitor.registerCallback(mUpdateCallback);
- // Disable alternate unlock right after boot until things have settled.
- mUpdateMonitor.setAlternateUnlockEnabled(false);
+ // Suppress biometric unlock right after boot until things have settled if it is the
+ // selected security method, otherwise unsuppress it. It must be unsuppressed if it is
+ // not the selected security method for the following reason: if the user starts
+ // without a screen lock selected, the biometric unlock would be suppressed the first
+ // time they try to use it.
+ //
+ // Note that the biometric unlock will still not show if it is not the selected method.
+ // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the
+ // selected method.
+ if (mLockPatternUtils.usingBiometricWeak()
+ && mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
+ mUpdateMonitor.setAlternateUnlockEnabled(false);
+ } else {
+ mUpdateMonitor.setAlternateUnlockEnabled(true);
+ }
doKeyguardLocked();
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index c89e880..ddded8e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -101,10 +101,21 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
}
- public void onPageSwitch(View newPage, int newPageIndex) {
+ public void onPageSwitching(View newPage, int newPageIndex) {
+ if (mPagedView != null && mChallengeLayout instanceof SlidingChallengeLayout) {
+ boolean isCameraPage = newPage instanceof CameraWidgetFrame;
+ ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
+ }
+ }
+
+ public void onPageSwitched(View newPage, int newPageIndex) {
// Reset the previous page size and ensure the current page is sized appropriately.
// We only modify the page state if it is not currently under control by the slider.
// This prevents conflicts.
+
+ // If the page hasn't switched, don't bother with any of this
+ if (mCurrentPage != newPageIndex) return;
+
if (mPagedView != null && mChallengeLayout != null) {
KeyguardWidgetFrame prevPage = mPagedView.getWidgetPageAt(mCurrentPage);
if (prevPage != null && mCurrentPage != mPageListeningToSlider) {
@@ -162,7 +173,6 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
if (!challengeOverlapping) {
frame.resetSize();
}
- frame.onChallengeActive(mChallengeLayout.isChallengeShowing());
frame.hideFrame(this);
if (challengeOverlapping) {
@@ -196,8 +206,6 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
}
// View is on the move. Pause the security view until it completes.
mKeyguardSecurityContainer.onPause();
-
- frame.onChallengeActive(true);
}
mLastScrollState = scrollState;
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index b1ff049..9ffabf8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -42,6 +43,10 @@ public class KeyguardWidgetFrame extends FrameLayout {
new PorterDuffXfermode(PorterDuff.Mode.ADD);
static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f;
+ static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000;
+
+ // Temporarily disable this for the time being until we know why the gfx is messing up
+ static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true;
private int mGradientColor;
private LinearGradient mForegroundGradient;
@@ -62,7 +67,20 @@ public class KeyguardWidgetFrame extends FrameLayout {
private float mBackgroundAlphaMultiplier = 1.0f;
private Drawable mBackgroundDrawable;
private Rect mBackgroundRect = new Rect();
+ private int mLastMeasuredWidth = -1;
+ private int mLastMeasuredHeight = 1;
+
+ // These variables are all needed in order to size things properly before we're actually
+ // measured.
private int mSmallWidgetHeight;
+ private int mSmallFrameHeight;
+ private boolean mWidgetLockedSmall = false;
+ private int mMaxChallengeTop = -1;
+
+ // This will hold the width value before we've actually been measured
+ private int mFrameHeight;
+
+ private boolean mIsHoveringOverDeleteDropTarget;
// Multiple callers may try and adjust the alpha of the frame. When a caller shows
// the outlines, we give that caller control, and nobody else can fade them out.
@@ -98,8 +116,13 @@ public class KeyguardWidgetFrame extends FrameLayout {
cancelLongPress();
}
- public void setMaxChallengeTop(int top) {
- mSmallWidgetHeight = top - getPaddingTop();
+ void setIsHoveringOverDeleteDropTarget(boolean isHovering) {
+ if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+ if (mIsHoveringOverDeleteDropTarget != isHovering) {
+ mIsHoveringOverDeleteDropTarget = isHovering;
+ invalidate();
+ }
+ }
}
@Override
@@ -163,6 +186,12 @@ public class KeyguardWidgetFrame extends FrameLayout {
c.drawRect(mForegroundRect, mGradientPaint);
}
+ private void drawHoveringOverDeleteOverlay(Canvas c) {
+ if (mIsHoveringOverDeleteDropTarget) {
+ c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR);
+ }
+ }
+
protected void drawBg(Canvas canvas) {
if (mBackgroundAlpha > 0.0f) {
Drawable bg = mBackgroundDrawable;
@@ -175,9 +204,16 @@ public class KeyguardWidgetFrame extends FrameLayout {
@Override
protected void dispatchDraw(Canvas canvas) {
+ if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+ canvas.save();
+ }
drawBg(canvas);
super.dispatchDraw(canvas);
drawGradientOverlay(canvas);
+ if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+ drawHoveringOverDeleteOverlay(canvas);
+ canvas.restore();
+ }
}
/**
@@ -220,8 +256,10 @@ public class KeyguardWidgetFrame extends FrameLayout {
View content = getContent();
if (content instanceof AppWidgetHostView) {
return ((AppWidgetHostView) content).getAppWidgetId();
- } else {
+ } else if (content instanceof KeyguardStatusView) {
return ((KeyguardStatusView) content).getAppWidgetId();
+ } else {
+ return AppWidgetManager.INVALID_APPWIDGET_ID;
}
}
@@ -260,22 +298,6 @@ public class KeyguardWidgetFrame extends FrameLayout {
}
/**
- * Set the top location of the challenge.
- *
- * @param top The top of the challenge, in _local_ coordinates, or -1 to indicate the challenge
- * is down.
- */
- private void setChallengeTop(int top, boolean updateWidgetSize) {
- // The widget starts below the padding, and extends to the top of the challengs.
- int widgetHeight = top - getPaddingTop();
- int frameHeight = top + getPaddingBottom();
- setFrameHeight(frameHeight);
- if (updateWidgetSize) {
- setWidgetHeight(widgetHeight);
- }
- }
-
- /**
* Depending on whether the security is up, the widget size needs to change
*
* @param height The height of the widget, -1 for full height
@@ -295,28 +317,51 @@ public class KeyguardWidgetFrame extends FrameLayout {
}
}
+ public void setMaxChallengeTop(int top) {
+ boolean dirty = mMaxChallengeTop != top;
+ mSmallWidgetHeight = top - getPaddingTop();
+ mSmallFrameHeight = top + getPaddingBottom();
+ if (dirty && mIsSmall) {
+ setWidgetHeight(mSmallWidgetHeight);
+ setFrameHeight(mSmallFrameHeight);
+ } else if (dirty && mWidgetLockedSmall) {
+ setWidgetHeight(mSmallWidgetHeight);
+ }
+ }
+
public boolean isSmall() {
return mIsSmall;
}
public void adjustFrame(int challengeTop) {
- setChallengeTop(challengeTop, false);
+ int frameHeight = challengeTop + getPaddingBottom();
+ setFrameHeight(frameHeight);
}
public void shrinkWidget() {
mIsSmall = true;
- setChallengeTop(mSmallWidgetHeight, true);
+ setWidgetHeight(mSmallWidgetHeight);
+ setFrameHeight(mSmallFrameHeight);
+ }
+
+ public void setWidgetLockedSmall(boolean locked) {
+ if (locked) {
+ setWidgetHeight(mSmallWidgetHeight);
+ }
+ mWidgetLockedSmall = locked;
}
public void resetSize() {
mIsSmall = false;
+ if (!mWidgetLockedSmall) {
+ setWidgetHeight(LayoutParams.MATCH_PARENT);
+ }
setFrameHeight(getMeasuredHeight());
- setWidgetHeight(LayoutParams.MATCH_PARENT);
}
public void setFrameHeight(int height) {
- height = Math.min(height, getMeasuredHeight());
- mBackgroundRect.set(0, 0, getMeasuredWidth(), height);
+ mFrameHeight = height;
+ mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight()));
invalidate();
}
@@ -356,10 +401,38 @@ public class KeyguardWidgetFrame extends FrameLayout {
mGradientColor, 0, Shader.TileMode.CLAMP);
mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
mGradientColor, 0, Shader.TileMode.CLAMP);
- mBackgroundRect.set(0, 0, w, h);
+
+ if (!mIsSmall) {
+ mFrameHeight = h;
+ }
+
+ mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight));
invalidate();
}
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ performAppWidgetSizeCallbacksIfNecessary();
+ }
+
+ private void performAppWidgetSizeCallbacksIfNecessary() {
+ View content = getContent();
+ if (!(content instanceof AppWidgetHostView)) return;
+
+ boolean sizeDirty = content.getMeasuredWidth() != mLastMeasuredWidth ||
+ content.getMeasuredHeight() != mLastMeasuredHeight;
+ if (sizeDirty) {
+
+ }
+
+ AppWidgetHostView awhv = (AppWidgetHostView) content;
+ float density = getResources().getDisplayMetrics().density;
+
+ int width = (int) (content.getMeasuredWidth() / density);
+ int height = (int) (content.getMeasuredHeight() / density);
+ awhv.updateAppWidgetSize(null, width, height, width, height, true);
+ }
+
void setOverScrollAmount(float r, boolean left) {
if (Float.compare(mOverScrollAmount, r) != 0) {
mOverScrollAmount = r;
@@ -373,12 +446,8 @@ public class KeyguardWidgetFrame extends FrameLayout {
// hook for subclasses
}
- public boolean onUserInteraction(int action) {
+ public boolean onUserInteraction(MotionEvent event) {
// hook for subclasses
return false;
}
-
- public void onChallengeActive(boolean challengeActive) {
- // hook for subclasses
- }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index f04c4df..acb2913 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -21,6 +21,8 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
@@ -31,9 +33,9 @@ import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.internal.R;
@@ -117,7 +119,14 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
@Override
- public void onPageSwitch(View newPage, int newPageIndex) {
+ public void onPageSwitching(View newPage, int newPageIndex) {
+ if (mViewStateManager != null) {
+ mViewStateManager.onPageSwitching(newPage, newPageIndex);
+ }
+ }
+
+ @Override
+ public void onPageSwitched(View newPage, int newPageIndex) {
boolean showingStatusWidget = false;
if (newPage instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) newPage;
@@ -156,7 +165,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
}
if (mViewStateManager != null) {
- mViewStateManager.onPageSwitch(newPage, newPageIndex);
+ mViewStateManager.onPageSwitched(newPage, newPageIndex);
}
}
@@ -177,7 +186,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
@Override
public boolean onTouchEvent(MotionEvent ev) {
KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
- if (currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev.getAction())) {
+ if (currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev)) {
return true;
}
return super.onTouchEvent(ev);
@@ -250,10 +259,23 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
lp.gravity = Gravity.TOP;
+
// The framework adds a default padding to AppWidgetHostView. We don't need this padding
// for the Keyguard, so we override it to be 0.
widget.setPadding(0, 0, 0, 0);
frame.addView(widget, lp);
+
+ // We set whether or not this widget supports vertical resizing.
+ if (widget instanceof AppWidgetHostView) {
+ AppWidgetHostView awhv = (AppWidgetHostView) widget;
+ AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
+ if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
+ frame.setWidgetLockedSmall(false);
+ } else {
+ // Lock the widget to be small.
+ frame.setWidgetLockedSmall(true);
+ }
+ }
} else {
frame = (KeyguardWidgetFrame) widget;
}
@@ -549,20 +571,20 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
// coordinate relative to our children, hence we subtract the top padding.s
maxChallengeTop = top - getPaddingTop();
challengeShowing = scl.isChallengeShowing();
- }
-
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- KeyguardWidgetFrame frame = getWidgetPageAt(i);
- frame.setMaxChallengeTop(maxChallengeTop);
- // On the very first measure pass, if the challenge is showing, we need to make sure
- // that the widget on the current page is small.
- if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
- frame.shrinkWidget();
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ KeyguardWidgetFrame frame = getWidgetPageAt(i);
+ frame.setMaxChallengeTop(maxChallengeTop);
+ // On the very first measure pass, if the challenge is showing, we need to make sure
+ // that the widget on the current page is small.
+ if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
+ frame.shrinkWidget();
+ }
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mHasMeasure = true;
}
void animateOutlinesAndSidePages(final boolean show) {
@@ -695,4 +717,10 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
return indexOfChild((KeyguardWidgetFrame)view.getParent());
}
}
+
+ @Override
+ protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
+ KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
+ child.setIsHoveringOverDeleteDropTarget(isHovering);
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java b/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java
new file mode 100644
index 0000000..818108c
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.policy.impl.keyguard;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+/**
+ * Hover listener that implements lift-to-activate interaction for
+ * accessibility. May be added to multiple views.
+ */
+class LiftToActivateListener implements View.OnHoverListener {
+ /** Manager used to query accessibility enabled state. */
+ private final AccessibilityManager mAccessibilityManager;
+
+ private boolean mCachedClickableState;
+
+ public LiftToActivateListener(Context context) {
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ }
+
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ // When touch exploration is turned on, lifting a finger while
+ // inside the view bounds should perform a click action.
+ if (mAccessibilityManager.isEnabled()
+ && mAccessibilityManager.isTouchExplorationEnabled()) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ // Lift-to-type temporarily disables double-tap
+ // activation by setting the view as not clickable.
+ mCachedClickableState = v.isClickable();
+ v.setClickable(false);
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+ if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
+ && (x < v.getWidth() - v.getPaddingRight())
+ && (y < v.getHeight() - v.getPaddingBottom())) {
+ v.performClick();
+ }
+ v.setClickable(mCachedClickableState);
+ break;
+ }
+ }
+
+ // Pass the event to View.onHoverEvent() to handle accessibility.
+ v.onHoverEvent(event);
+
+ // Consume the event so it doesn't fall through to other views.
+ return true;
+ }
+} \ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
index b38eb28..3bc39eb 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
@@ -47,6 +47,7 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
private OnBouncerStateChangedListener mBouncerListener;
private final Rect mTempRect = new Rect();
+ private final Context mContext;
private final OnClickListener mScrimClickListener = new OnClickListener() {
@Override
@@ -66,6 +67,8 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mContext = context;
+
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_orientation,
@@ -173,6 +176,8 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
throw new IllegalArgumentException(
"MultiPaneChallengeLayout must be measured with an exact size");
}
+ float squashedLayoutThreshold =
+ mContext.getResources().getDimension(R.dimen.kg_squashed_layout_threshold);
final int width = MeasureSpec.getSize(widthSpec);
final int height = MeasureSpec.getSize(heightSpec);
@@ -208,28 +213,32 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
mUserSwitcherView = child;
if (child.getVisibility() == GONE) continue;
-
- int adjustedWidthSpec = widthSpec;
- int adjustedHeightSpec = heightSpec;
- if (lp.maxWidth >= 0) {
- adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
- Math.min(lp.maxWidth, MeasureSpec.getSize(widthSpec)),
- MeasureSpec.EXACTLY);
- }
- if (lp.maxHeight >= 0) {
- adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
- Math.min(lp.maxHeight, MeasureSpec.getSize(heightSpec)),
- MeasureSpec.EXACTLY);
- }
- // measureChildWithMargins will resolve layout direction for the LayoutParams
- measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-
- // Only subtract out space from one dimension. Favor vertical.
- // Offset by 1.5x to add some balance along the other edge.
- if (Gravity.isVertical(lp.gravity)) {
- heightUsed += child.getMeasuredHeight() * 1.5f;
- } else if (Gravity.isHorizontal(lp.gravity)) {
- widthUsed += child.getMeasuredWidth() * 1.5f;
+ if (height < squashedLayoutThreshold) {
+ int zero = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
+ measureChild(child, zero, zero);
+ } else {
+ int adjustedWidthSpec = widthSpec;
+ int adjustedHeightSpec = heightSpec;
+ if (lp.maxWidth >= 0) {
+ adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+ Math.min(lp.maxWidth, MeasureSpec.getSize(widthSpec)),
+ MeasureSpec.EXACTLY);
+ }
+ if (lp.maxHeight >= 0) {
+ adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+ Math.min(lp.maxHeight, MeasureSpec.getSize(heightSpec)),
+ MeasureSpec.EXACTLY);
+ }
+ // measureChildWithMargins will resolve layout direction for the LayoutParams
+ measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
+
+ // Only subtract out space from one dimension. Favor vertical.
+ // Offset by 1.5x to add some balance along the other edge.
+ if (Gravity.isVertical(lp.gravity)) {
+ heightUsed += child.getMeasuredHeight() * 1.5f;
+ } else if (Gravity.isHorizontal(lp.gravity)) {
+ widthUsed += child.getMeasuredWidth() * 1.5f;
+ }
}
} else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
setScrimView(child);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
index ca36007..a0038bc 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
@@ -22,9 +22,7 @@ import android.text.SpannableStringBuilder;
import android.text.style.TextAppearanceSpan;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.accessibility.AccessibilityManager;
import android.widget.Button;
import android.widget.TextView;
@@ -51,7 +49,8 @@ public class NumPadKey extends Button {
}
}
}
- if (mTextView != null) {
+ // check for time-based lockouts
+ if (mTextView != null && mTextView.isEnabled()) {
mTextView.append(String.valueOf(mDigit));
}
doHapticKeyClick();
@@ -75,6 +74,7 @@ public class NumPadKey extends Button {
setOnClickListener(mListener);
setOnHoverListener(new LiftToActivateListener(context));
+ setAccessibilityDelegate(new ObscureSpeechDelegate(context));
mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
@@ -89,6 +89,7 @@ public class NumPadKey extends Button {
final String extra = sKlondike[mDigit];
final int extraLen = extra.length();
if (extraLen > 0) {
+ builder.append(" ");
builder.append(extra);
builder.setSpan(
new TextAppearanceSpan(context, R.style.TextAppearance_NumPadKey_Klondike),
@@ -99,6 +100,14 @@ public class NumPadKey extends Button {
setText(builder);
}
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ // Reset the "announced headset" flag when detached.
+ ObscureSpeechDelegate.sAnnouncedHeadset = false;
+ }
+
public void setTextView(TextView tv) {
mTextView = tv;
}
@@ -116,45 +125,4 @@ public class NumPadKey extends Button {
| HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
}
-
- /**
- * Hover listener that implements lift-to-activate interaction for
- * accessibility. May be added to multiple views.
- */
- static class LiftToActivateListener implements View.OnHoverListener {
- /** Manager used to query accessibility enabled state. */
- private final AccessibilityManager mAccessibilityManager;
-
- public LiftToActivateListener(Context context) {
- mAccessibilityManager = (AccessibilityManager) context.getSystemService(
- Context.ACCESSIBILITY_SERVICE);
- }
-
- @Override
- public boolean onHover(View v, MotionEvent event) {
- // When touch exploration is turned on, lifting a finger while
- // inside the view bounds should perform a click action.
- if (mAccessibilityManager.isEnabled()
- && mAccessibilityManager.isTouchExplorationEnabled()) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- // Lift-to-type temporarily disables double-tap
- // activation.
- v.setClickable(false);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- final int x = (int) event.getX();
- final int y = (int) event.getY();
- if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
- && (x < v.getWidth() - v.getPaddingRight())
- && (y < v.getHeight() - v.getPaddingBottom())) {
- v.performClick();
- }
- v.setClickable(true);
- break;
- }
- }
- return false;
- }
- }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java
new file mode 100644
index 0000000..af043ab
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 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.policy.impl.keyguard;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.AudioManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.R;
+
+/**
+ * Accessibility delegate that obscures speech for a view when the user has
+ * not turned on the "speak passwords" preference and is not listening
+ * through headphones.
+ */
+class ObscureSpeechDelegate extends AccessibilityDelegate {
+ /** Whether any client has announced the "headset" notification. */
+ static boolean sAnnouncedHeadset = false;
+
+ private final ContentResolver mContentResolver;
+ private final AudioManager mAudioManager;
+
+ public ObscureSpeechDelegate(Context context) {
+ mContentResolver = context.getContentResolver();
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ @Override
+ public void sendAccessibilityEvent(View host, int eventType) {
+ super.sendAccessibilityEvent(host, eventType);
+
+ // Play the "headset required" announcement the first time the user
+ // places accessibility focus on a key.
+ if ((eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED)
+ && !sAnnouncedHeadset && shouldObscureSpeech()) {
+ sAnnouncedHeadset = true;
+ host.announceForAccessibility(host.getContext().getString(
+ R.string.keyboard_headset_required_to_hear_password));
+ }
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(host, event);
+
+ if ((event.getEventType() != AccessibilityEvent.TYPE_ANNOUNCEMENT)
+ && shouldObscureSpeech()) {
+ event.getText().clear();
+ event.setContentDescription(host.getContext().getString(
+ R.string.keyboard_password_character_no_headset));
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+
+ if (shouldObscureSpeech()) {
+ final Context ctx = host.getContext();
+ info.setText(null);
+ info.setContentDescription(
+ ctx.getString(R.string.keyboard_password_character_no_headset));
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean shouldObscureSpeech() {
+ // The user can optionally force speaking passwords.
+ if (Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0) {
+ return false;
+ }
+
+ // Always speak if the user is listening through headphones.
+ if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) {
+ return false;
+ }
+
+ // Don't speak since this key is used to type a password.
+ return true;
+ }
+} \ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 6eeada5..00a0aed 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -48,6 +48,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import com.android.internal.R;
@@ -205,6 +206,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300;
private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
+ private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
private float mMinScale = 1f;
protected View mDragView;
private AnimatorSet mZoomInOutAnim;
@@ -228,18 +230,25 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Convenience/caching
private Matrix mTmpInvMatrix = new Matrix();
private float[] mTmpPoint = new float[2];
+ private Rect mTmpRect = new Rect();
// Fling to delete
private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
private float FLING_TO_DELETE_FRICTION = 0.035f;
// The degrees specifies how much deviation from the up vector to still consider a fling "up"
- private float FLING_TO_DELETE_MAX_FLING_DEGREES = 35f;
- private int FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+ private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
protected int mFlingToDeleteThresholdVelocity = -1400;
- private boolean mIsFlingingToDelete = false;
+ // Drag to delete
+ private boolean mDeferringForDelete = false;
+ private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+ private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
+
+ // Drop to delete
+ private View mDeleteDropTarget;
public interface PageSwitchListener {
- void onPageSwitch(View newPage, int newPageIndex);
+ void onPageSwitching(View newPage, int newPageIndex);
+ void onPageSwitched(View newPage, int newPageIndex);
}
public PagedView(Context context) {
@@ -293,19 +302,23 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
setOnHierarchyChangeListener(this);
}
+ void setDeleteDropTarget(View v) {
+ mDeleteDropTarget = v;
+ }
+
// Convenience methods to map points from self to parent and vice versa
- float[] mapPointFromSelfToParent(float x, float y) {
+ float[] mapPointFromViewToParent(View v, float x, float y) {
mTmpPoint[0] = x;
mTmpPoint[1] = y;
- getMatrix().mapPoints(mTmpPoint);
- mTmpPoint[0] += getLeft();
- mTmpPoint[1] += getTop();
+ v.getMatrix().mapPoints(mTmpPoint);
+ mTmpPoint[0] += v.getLeft();
+ mTmpPoint[1] += v.getTop();
return mTmpPoint;
}
- float[] mapPointFromParentToSelf(float x, float y) {
- mTmpPoint[0] = x - getLeft();
- mTmpPoint[1] = y - getTop();
- getMatrix().invert(mTmpInvMatrix);
+ float[] mapPointFromParentToView(View v, float x, float y) {
+ mTmpPoint[0] = x - v.getLeft();
+ mTmpPoint[1] = y - v.getTop();
+ v.getMatrix().invert(mTmpInvMatrix);
mTmpInvMatrix.mapPoints(mTmpPoint);
return mTmpPoint;
}
@@ -328,7 +341,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
public void setScaleX(float scaleX) {
super.setScaleX(scaleX);
if (isReordering(true)) {
- float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+ float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
mLastMotionX = p[0];
mLastMotionY = p[1];
updateDragViewTranslationDuringDrag();
@@ -356,7 +369,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
mPageSwitchListener = pageSwitchListener;
if (mPageSwitchListener != null) {
- mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+ mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
}
}
@@ -415,6 +428,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
* Sets the current page.
*/
void setCurrentPage(int currentPage) {
+ notifyPageSwitching(currentPage);
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
@@ -428,7 +442,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
updateCurrentPageScroll();
updateScrollingIndicator();
- notifyPageSwitchListener();
+ notifyPageSwitched();
invalidate();
}
@@ -436,9 +450,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mOnlyAllowEdgeSwipes = enable;
}
- protected void notifyPageSwitchListener() {
+ protected void notifyPageSwitching(int whichPage) {
if (mPageSwitchListener != null) {
- mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+ mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
+ }
+ }
+
+ protected void notifyPageSwitched() {
+ if (mPageSwitchListener != null) {
+ mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
}
}
@@ -511,7 +531,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Update the last motion events when scrolling
if (isReordering(true)) {
- float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+ float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
mLastMotionX = p[0];
mLastMotionY = p[1];
updateDragViewTranslationDuringDrag();
@@ -532,13 +552,14 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
} else if (mNextPage != INVALID_PAGE) {
mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
mNextPage = INVALID_PAGE;
- notifyPageSwitchListener();
+ notifyPageSwitched();
// We don't want to trigger a page end moving unless the page has settled
// and the user has stopped scrolling
if (mTouchState == TOUCH_STATE_REST) {
pageEndMoving();
}
+
onPostReorderingAnimationCompleted();
return true;
}
@@ -632,7 +653,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// ensure that the cache is filled with good values.
invalidateCachedOffsets();
- if (mChildCountOnLastMeasure != getChildCount() && !mIsFlingingToDelete) {
+ if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
setCurrentPage(mCurrentPage);
}
mChildCountOnLastMeasure = getChildCount();
@@ -856,7 +877,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
final int pageCount = getChildCount();
if (pageCount > 0) {
getVisiblePages(mTempVisiblePagesRange);
- boundByReorderablePages(isReordering(false), mTempVisiblePagesRange);
final int leftScreen = mTempVisiblePagesRange[0];
final int rightScreen = mTempVisiblePagesRange[1];
if (leftScreen != -1 && rightScreen != -1) {
@@ -1038,7 +1058,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mDownScrollX = getScrollX();
mLastMotionX = x;
mLastMotionY = y;
- float[] p = mapPointFromSelfToParent(x, y);
+ float[] p = mapPointFromViewToParent(this, x, y);
mParentDownMotionX = p[0];
mParentDownMotionY = p[1];
mLastMotionXRemainder = 0;
@@ -1270,7 +1290,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mDownMotionX = mLastMotionX = ev.getX();
mDownMotionY = mLastMotionY = ev.getY();
mDownScrollX = getScrollX();
- float[] p = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+ float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = p[0];
mParentDownMotionY = p[1];
mLastMotionXRemainder = 0;
@@ -1322,7 +1342,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Update the parent down so that our zoom animations take this new movement into
// account
- float[] pt = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+ float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = pt[0];
mParentDownMotionY = pt[1];
updateDragViewTranslationDuringDrag();
@@ -1331,11 +1351,16 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
final int dragViewIndex = indexOfChild(mDragView);
int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
getViewportWidth());
- int leftBufferEdge = (int) (mapPointFromSelfToParent(mViewport.left, 0)[0]
+ int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
+ bufferSize);
- int rightBufferEdge = (int) (mapPointFromSelfToParent(mViewport.right, 0)[0]
+ int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
- bufferSize);
+ // Change the drag view if we are hovering over the drop target
+ boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
+ (int) mParentDownMotionX, (int) mParentDownMotionY);
+ setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
+
if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
@@ -1352,7 +1377,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
final int pageUnderPointIndex = pageIndexToSnapTo;
- if (pageUnderPointIndex > -1) {
+ if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
boundByReorderablePages(true, mTempVisiblePagesRange);
@@ -1485,13 +1510,29 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_REORDERING) {
+ // Update the last motion position
+ mLastMotionX = ev.getX();
+ mLastMotionY = ev.getY();
+
+ // Update the parent down so that our zoom animations take this new movement into
+ // account
+ float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+ mParentDownMotionX = pt[0];
+ mParentDownMotionY = pt[1];
+ updateDragViewTranslationDuringDrag();
+ boolean handledFling = false;
if (!DISABLE_FLING_TO_DELETE) {
// Check the velocity and see if we are flinging-to-delete
PointF flingToDeleteVector = isFlingingToDelete();
if (flingToDeleteVector != null) {
onFlingToDelete(flingToDeleteVector);
+ handledFling = true;
}
}
+ if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
+ (int) mParentDownMotionY)) {
+ onDropToDelete();
+ }
} else {
onUnhandledTap(ev);
}
@@ -1743,7 +1784,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
mNextPage = whichPage;
-
+ notifyPageSwitching(whichPage);
View focusedChild = getFocusedChild();
if (focusedChild != null && whichPage != mCurrentPage &&
focusedChild == getPageAt(mCurrentPage)) {
@@ -1761,13 +1802,14 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
if (!mScroller.isFinished()) mScroller.abortAnimation();
mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
- notifyPageSwitchListener();
+ notifyPageSwitched();
// Trigger a compute() to finish switching pages if necessary
if (immediate) {
computeScroll();
}
+ mForceScreenScrolled = true;
invalidate();
}
@@ -1991,6 +2033,23 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mZoomInOutAnim.playTogether(
ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
+ mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Show the delete drop target
+ if (mDeleteDropTarget != null) {
+ mDeleteDropTarget.setVisibility(View.VISIBLE);
+ mDeleteDropTarget.animate().alpha(1f)
+ .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mDeleteDropTarget.setAlpha(0f);
+ }
+ });
+ }
+ }
+ });
mZoomInOutAnim.start();
return true;
}
@@ -2007,6 +2066,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mTouchState = TOUCH_STATE_REORDERING;
mIsReordering = true;
+ // Mark all the non-widget pages as invisible
+ getVisiblePages(mTempVisiblePagesRange);
+ boundByReorderablePages(true, mTempVisiblePagesRange);
+ for (int i = 0; i < getPageCount(); ++i) {
+ if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+ getPageAt(i).setAlpha(0f);
+ }
+ }
+
// We must invalidate to trigger a redraw to update the layers such that the drag view
// is always drawn on top
invalidate();
@@ -2028,6 +2096,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
R.string.keyguard_accessibility_widget_reorder_end));
}
mIsReordering = false;
+
+ // Mark all the non-widget pages as visible again
+ getVisiblePages(mTempVisiblePagesRange);
+ boundByReorderablePages(true, mTempVisiblePagesRange);
+ for (int i = 0; i < getPageCount(); ++i) {
+ if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+ getPageAt(i).setAlpha(1f);
+ }
+ }
}
public boolean startReordering() {
@@ -2072,7 +2149,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
onEndReordering();
}
};
- if (!mIsFlingingToDelete) {
+ if (!mDeferringForDelete) {
mPostReorderingPreZoomInRunnable = new Runnable() {
public void run() {
zoomIn(onCompleteRunnable);
@@ -2086,7 +2163,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Animate the drag view back to the front position
animateDragViewToOriginalPosition();
} else {
- zoomIn(onCompleteRunnable);
+ // Handled in post-delete-animation-callbacks
}
}
@@ -2103,6 +2180,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
ObjectAnimator.ofFloat(this, "scaleY", 1f));
mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ // Hide the delete drop target
+ if (mDeleteDropTarget != null) {
+ mDeleteDropTarget.animate().alpha(0f)
+ .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDeleteDropTarget.setVisibility(View.GONE);
+ }
+ });
+ }
+ }
+ @Override
public void onAnimationCancel(Animator animation) {
mDragView = null;
}
@@ -2186,6 +2277,97 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
};
+ private Runnable createPostDeleteAnimationRunnable(final View dragView) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ int dragViewIndex = indexOfChild(dragView);
+
+ // For each of the pages around the drag view, animate them from the previous
+ // position to the new position in the layout (as a result of the drag view moving
+ // in the layout)
+ // NOTE: We can make an assumption here because we have side-bound pages that we
+ // will always have pages to animate in from the left
+ getVisiblePages(mTempVisiblePagesRange);
+ boundByReorderablePages(true, mTempVisiblePagesRange);
+ boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
+ boolean slideFromLeft = (isLastWidgetPage ||
+ dragViewIndex > mTempVisiblePagesRange[0]);
+
+ // Setup the scroll to the correct page before we swap the views
+ if (slideFromLeft) {
+ snapToPageImmediately(dragViewIndex - 1);
+ }
+
+ int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
+ int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
+ int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
+ int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
+ ArrayList<Animator> animations = new ArrayList<Animator>();
+ for (int i = lowerIndex; i <= upperIndex; ++i) {
+ View v = getChildAt(i);
+ // dragViewIndex < pageUnderPointIndex, so after we remove the
+ // drag view all subsequent views to pageUnderPointIndex will
+ // shift down.
+ int oldX = 0;
+ int newX = 0;
+ if (slideFromLeft) {
+ if (i == 0) {
+ // Simulate the page being offscreen with the page spacing
+ oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
+ - mPageSpacing;
+ } else {
+ oldX = getViewportOffsetX() + getChildOffset(i - 1);
+ }
+ newX = getViewportOffsetX() + getChildOffset(i);
+ } else {
+ oldX = getChildOffset(i) - getChildOffset(i - 1);
+ newX = 0;
+ }
+
+ // Animate the view translation from its old position to its new
+ // position
+ AnimatorSet anim = (AnimatorSet) v.getTag();
+ if (anim != null) {
+ anim.cancel();
+ }
+
+ // Note: Hacky, but we want to skip any optimizations to not draw completely
+ // hidden views
+ v.setAlpha(Math.max(v.getAlpha(), 0.01f));
+ v.setTranslationX(oldX - newX);
+ anim = new AnimatorSet();
+ anim.playTogether(
+ ObjectAnimator.ofFloat(v, "translationX", 0f),
+ ObjectAnimator.ofFloat(v, "alpha", 1f));
+ animations.add(anim);
+ v.setTag(anim);
+ }
+
+ AnimatorSet slideAnimations = new AnimatorSet();
+ slideAnimations.playTogether(animations);
+ slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
+ slideAnimations.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ final Runnable onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mDeferringForDelete = false;
+ onEndReordering();
+ }
+ };
+ zoomIn(onCompleteRunnable);
+ }
+ });
+ slideAnimations.start();
+
+ removeView(dragView);
+ onRemoveView(dragView);
+ }
+ };
+ }
+
public void onFlingToDelete(PointF vel) {
final long startTime = AnimationUtils.currentAnimationTimeMillis();
@@ -2222,59 +2404,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
from, startTime, FLING_TO_DELETE_FRICTION);
- final Runnable onAnimationEndRunnable = new Runnable() {
- @Override
- public void run() {
- int dragViewIndex = indexOfChild(dragView);
- // Setup the scroll to the correct page before we swap the views
- snapToPageImmediately(dragViewIndex - 1);
-
- // For each of the pages around the drag view, animate them from the previous
- // position to the new position in the layout (as a result of the drag view moving
- // in the layout)
- // NOTE: We can make an assumption here because we have side-bound pages that we
- // will always have pages to animate in from the left
- int lowerIndex = 0;
- int upperIndex = dragViewIndex - 1;
- for (int i = lowerIndex; i <= upperIndex; ++i) {
- View v = getChildAt(i);
- // dragViewIndex < pageUnderPointIndex, so after we remove the
- // drag view all subsequent views to pageUnderPointIndex will
- // shift down.
- int oldX = 0;
- if (i == 0) {
- oldX = -(getViewportOffsetX() + getChildOffset(i));
- } else {
- oldX = getViewportOffsetX() + getChildOffset(i - 1);
- }
- int newX = getViewportOffsetX() + getChildOffset(i);
-
- // Animate the view translation from its old position to its new
- // position
- AnimatorSet anim = (AnimatorSet) v.getTag();
- if (anim != null) {
- anim.cancel();
- }
-
- v.setTranslationX(oldX - newX);
- anim = new AnimatorSet();
- anim.setDuration(FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
- anim.playTogether(
- ObjectAnimator.ofFloat(v, "translationX", 0f));
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mIsFlingingToDelete = false;
- }
- });
- anim.start();
- v.setTag(anim);
- }
-
- removeView(dragView);
- onRemoveView(dragView);
- }
- };
+ final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
// Create and start the animation
ValueAnimator mDropAnim = new ValueAnimator();
@@ -2288,11 +2418,57 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
});
mDropAnim.start();
- mIsFlingingToDelete = true;
+ mDeferringForDelete = true;
}
- /* Accessibility */
+ /* Drag to delete */
+ private boolean isHoveringOverDeleteDropTarget(int x, int y) {
+ if (mDeleteDropTarget != null) {
+ mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
+ return mTmpRect.contains(x, y);
+ }
+ return false;
+ }
+
+ protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
+
+ private void onDropToDelete() {
+ final View dragView = mDragView;
+ final float toScale = 0f;
+ final float toAlpha = 0f;
+
+ // Create and start the complex animation
+ ArrayList<Animator> animations = new ArrayList<Animator>();
+ AnimatorSet motionAnim = new AnimatorSet();
+ motionAnim.setInterpolator(new DecelerateInterpolator(2));
+ motionAnim.playTogether(
+ ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
+ ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
+ animations.add(motionAnim);
+
+ AnimatorSet alphaAnim = new AnimatorSet();
+ alphaAnim.setInterpolator(new LinearInterpolator());
+ alphaAnim.playTogether(
+ ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
+ animations.add(alphaAnim);
+
+ final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
+
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(animations);
+ anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ onAnimationEndRunnable.run();
+ }
+ });
+ anim.start();
+
+ mDeferringForDelete = true;
+ }
+
+ /* Accessibility */
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
index 6156143..16e2f9e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -16,6 +16,8 @@
package com.android.internal.policy.impl.keyguard;
+import com.android.internal.R;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -29,7 +31,6 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
-import android.util.MathUtils;
import android.util.Property;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -40,8 +41,6 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.widget.Scroller;
-import com.android.internal.R;
-
/**
* This layout handles interaction with the sliding security challenge views
* that overlay/resize other keyguard contents.
@@ -53,7 +52,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
// The drag handle is measured in dp above & below the top edge of the
// challenge view; these parameters change based on whether the challenge
// is open or closed.
- private static final int DRAG_HANDLE_CLOSED_ABOVE = 64; // dp
+ private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
@@ -67,7 +66,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
// Initialized during measurement from child layoutparams
private View mExpandChallengeView;
- private View mChallengeView;
+ private KeyguardSecurityContainer mChallengeView;
private View mScrimView;
private View mWidgetsView;
@@ -123,6 +122,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
private final Rect mTempRect = new Rect();
private boolean mHasGlowpad;
+ private boolean mChallengeInteractive = true;
static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
@@ -276,6 +276,13 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
}
+ public void setChallengeInteractive(boolean interactive) {
+ mChallengeInteractive = interactive;
+ if (mExpandChallengeView != null) {
+ mExpandChallengeView.setEnabled(interactive);
+ }
+ }
+
void animateHandle(boolean visible) {
if (mHandleAnimation != null) {
mHandleAnimation.cancel();
@@ -504,7 +511,9 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
if (mScrimView != null) {
mScrimView.setVisibility(VISIBLE);
}
-
+ if (mChallengeView != null) {
+ mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION);
+ }
// Mess with padding/margin to inset the bouncer frame.
// We have more space available to us otherwise.
if (mChallengeView != null) {
@@ -533,6 +542,9 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
+ if (mChallengeView != null) {
+ mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION);
+ }
animateFrame(false, true);
if (mBouncerListener != null) {
mBouncerListener.onBouncerStateChanged(false);
@@ -580,19 +592,17 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
for (int i = 0; i < count; i++) {
final float x = ev.getX(i);
final float y = ev.getY(i);
- if (!mIsBouncing && mActivePointerId == INVALID_POINTER
- && ((isInDragHandle(x, y) && MathUtils.sq(x - mGestureStartX)
- + MathUtils.sq(y - mGestureStartY) > mTouchSlopSquare)
- || crossedDragHandle(x, y, mGestureStartY)
+ if (!mIsBouncing && mChallengeInteractive && mActivePointerId == INVALID_POINTER
+ && (crossedDragHandle(x, y, mGestureStartY)
|| (isInChallengeView(x, y) &&
- mScrollState == SCROLL_STATE_SETTLING))) {
+ mScrollState == SCROLL_STATE_SETTLING))) {
mActivePointerId = ev.getPointerId(i);
mGestureStartX = x;
mGestureStartY = y;
mGestureStartChallengeBottom = getChallengeBottom();
mDragging = true;
mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
- } else if (isInChallengeView(x, y)) {
+ } else if (mChallengeShowing && isInChallengeView(x, y)) {
mBlockDrag = true;
}
}
@@ -630,7 +640,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
break;
case MotionEvent.ACTION_CANCEL:
- if (mDragging) {
+ if (mDragging && mChallengeInteractive) {
showChallenge(0);
}
resetTouch();
@@ -641,7 +651,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
break;
}
case MotionEvent.ACTION_UP:
- if (mDragging) {
+ if (mDragging && mChallengeInteractive) {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
}
@@ -657,7 +667,8 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
(isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
- && mActivePointerId == INVALID_POINTER) {
+ && mActivePointerId == INVALID_POINTER
+ && mChallengeInteractive) {
mGestureStartX = x;
mGestureStartY = y;
mActivePointerId = ev.getPointerId(i);
@@ -767,11 +778,19 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
private boolean crossedDragHandle(float x, float y, float initialY) {
+
final int challengeTop = mChallengeView.getTop();
- return x >= 0 &&
- x < getWidth() &&
- initialY < (challengeTop - getDragHandleSizeAbove()) &&
- y > challengeTop + getDragHandleSizeBelow();
+ final boolean horizOk = x >= 0 && x < getWidth();
+
+ final boolean vertOk;
+ if (mChallengeShowing) {
+ vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
+ y > challengeTop + getDragHandleSizeBelow();
+ } else {
+ vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
+ y < challengeTop - getDragHandleSizeAbove();
+ }
+ return horizOk && vertOk;
}
@Override
@@ -803,7 +822,11 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
throw new IllegalStateException(
"There may only be one child with layout_isChallenge=\"true\"");
}
- mChallengeView = child;
+ if (!(child instanceof KeyguardSecurityContainer)) {
+ throw new IllegalArgumentException(
+ "Challenge must be a KeyguardSecurityContainer");
+ }
+ mChallengeView = (KeyguardSecurityContainer) child;
if (mChallengeView != oldChallengeView) {
mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index d0dd9cf..daa82f2 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -599,7 +599,7 @@ class AppWidgetServiceImpl {
}
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
- mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET,
"bindAppWidgetId appWidgetId=" + appWidgetId + " provider=" + provider);
bindAppWidgetIdImpl(appWidgetId, provider, options);
}
@@ -607,7 +607,7 @@ class AppWidgetServiceImpl {
public boolean bindAppWidgetIdIfAllowed(
String packageName, int appWidgetId, ComponentName provider, Bundle options) {
try {
- mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, null);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null);
} catch (SecurityException se) {
if (!callerHasBindAppWidgetPermission(packageName)) {
return false;