am 841ce670: Merge commit \'81af21e67cd842d16d4b45e8a2d1ec56ff8d764f\' into jb-mr1-dev

* commit '841ce670b29180a157a084a9c0e803b13e92020c': (26 commits)
  hide the correct text, and more text, on bounce
  Improve PIN key layouts.
  Obscure speech for PIN password keys when no headset plugged in.
  Initial changes to allow dropping on delete target to remove widget.
  hide multiuser selector when IME is up.
  Block swipe up gesture if challenge non-interactive.
  Properly disable challenge handle.
  Disable disable back if using an alternate back icon.
  Disable security handle when swiping into camera widget.
  Import translations. DO NOT MERGE
  Fix small issue with previous CL
  Widget size policy, size callbacks
  Don't show security method until we actually return from the camera
  Fix whitespace problem and sync with prototype.
  PUK support.
  Fix build.
  SIM PIN support.
  Use clock's widget as the default keyguard widget
  Add configurable em-dash separator for all concatenated keyguard strings
  Cleaning up keyguard persistence threads when the pager is detached. (Bug 7460991)
  ...
This commit is contained in:
Baligh Uddin
2012-11-02 16:50:29 -07:00
committed by Android Git Automerger
42 changed files with 1482 additions and 763 deletions

View File

@@ -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);

View File

@@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -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"

View File

@@ -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>

View File

@@ -33,6 +33,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<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"

View File

@@ -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>

View File

@@ -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"

View File

@@ -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"
/>

View File

@@ -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"
>
<TextView android:id="@+id/pinEntry"
android:editable="true"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
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="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="vertical">
<LinearLayout
android:layout_height="0dip"
android:layout_width="match_parent"
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"
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"
androidprv:textView="@+id/pinEntry"
androidprv:digit="1"
/>
<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"
<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>
<!-- 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"
android:clickable="true"
/>
</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>

View File

@@ -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"
>
<TextView android:id="@+id/pinEntry"
android:editable="true"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
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="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="vertical">
<LinearLayout
android:layout_height="0dip"
android:layout_width="match_parent"
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"
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"
androidprv:textView="@+id/pinEntry"
androidprv:digit="1"
/>
<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"
<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>
<!-- 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"
android:clickable="true"
/>
</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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 />
@@ -3976,6 +3967,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 -->

View File

@@ -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">

View File

@@ -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" />

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -195,4 +195,9 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
@Override
public void showUsabilityHint() {
}
@Override
public int getWrongPasswordStringId() {
return R.string.kg_wrong_password;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
// 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;
}
});
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return mPinEntry.requestFocus(direction, previouslyFocusedRect);
}
mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_VARIATION_PASSWORD);
public void reset() {
// start fresh
mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
// 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) {
}
}

View File

@@ -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 {
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 int getPasswordTextViewId() {
return R.id.pinEntry;
}
@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);
final View ok = findViewById(R.id.key_enter);
if (ok != null) {
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doHapticKeyClick();
verifyPasswordAndUnlock();
}
});
}
// 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();
mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
reset();
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return mSimPinEntry.requestFocus(direction, previouslyFocusedRect);
}
public boolean needsInput() {
return false; // This view provides its own keypad
}
public void onPause() {
}
public void onResume() {
reset();
}
@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);
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
protected void verifyPasswordAndUnlock() {
mStateMachine.next();
}
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
}
}
@@ -259,22 +297,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
*
@@ -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
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
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);
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;
// 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);

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}
@@ -2102,6 +2179,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
ObjectAnimator.ofFloat(this, "scaleX", 1f),
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;
}
/* 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);

View File

@@ -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);
}

View File

@@ -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;