Merge "A new clock widget to create lock screen appwidgets" into jb-mr1-dev
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2af65b9..3dd640c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -80,6 +80,13 @@
public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
/**
+ * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
+ * @hide
+ */
+ public static final String
+ ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
+
+ /**
* Send this from your {@link AppWidgetHost} activity when you want to bind an AppWidget to
* display and bindAppWidgetIdIfAllowed returns false.
* <p>
@@ -224,13 +231,6 @@
public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
/**
- * An intent extra to pass to the AppWidget picker which allows the picker to filter
- * the list based on the {@link AppWidgetProviderInfo#widgetFeatures}.
- * @hide
- */
- public static final String EXTRA_FEATURES_FILTER = "featuresFilter";
-
- /**
* An intent extra to pass to the AppWidget picker to specify whether or not to sort
* the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
* @hide
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
index a017722..017801b 100644
--- a/core/java/com/android/internal/policy/IFaceLockInterface.aidl
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -23,7 +23,6 @@
void startUi(IBinder containingWindowToken, int x, int y, int width, int height,
boolean useLiveliness);
void stopUi();
- void makeInvisible();
void registerCallback(IFaceLockCallback cb);
void unregisterCallback(IFaceLockCallback cb);
}
diff --git a/core/java/com/android/internal/widget/FaceUnlockView.java b/core/java/com/android/internal/widget/FaceUnlockView.java
new file mode 100644
index 0000000..e3c1247
--- /dev/null
+++ b/core/java/com/android/internal/widget/FaceUnlockView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+public class FaceUnlockView extends RelativeLayout {
+ private static final String TAG = "FaceUnlockView";
+
+ public FaceUnlockView(Context context) {
+ this(context, null);
+ }
+
+ public FaceUnlockView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private int resolveMeasured(int measureSpec, int desired)
+ {
+ int result = 0;
+ int specSize = MeasureSpec.getSize(measureSpec);
+ switch (MeasureSpec.getMode(measureSpec)) {
+ case MeasureSpec.UNSPECIFIED:
+ result = desired;
+ break;
+ case MeasureSpec.AT_MOST:
+ result = Math.max(specSize, desired);
+ break;
+ case MeasureSpec.EXACTLY:
+ default:
+ result = specSize;
+ }
+ return result;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int minimumWidth = getSuggestedMinimumWidth();
+ final int minimumHeight = getSuggestedMinimumHeight();
+ int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
+ int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
+
+ final int chosenSize = Math.min(viewWidth, viewHeight);
+ final int newWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
+ final int newHeightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
+
+ super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f8c3b4d..3ee3c8c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -129,6 +129,11 @@
*/
public static final int ID_DEFAULT_STATUS_WIDGET = -2;
+ /**
+ * Intent extra that's used to tag the default widget when using the picker
+ */
+ public static final String EXTRA_DEFAULT_WIDGET = "com.android.settings.DEFAULT_WIDGET";
+
protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 92aa06a..a5aa713 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1901,6 +1901,13 @@
android:description="@string/permdesc_bindGadget"
android:protectionLevel="signature|system" />
+ <!-- Private permission, to restrict who can bring up a dialog to add a new
+ keyguard widget
+ @hide -->
+ <permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:protectionLevel="signature|system" />
+
<!-- Internal permission allowing an application to query/set which
applications can bind AppWidgets.
@hide -->
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index bb455bd..67ac1d5 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -50,14 +50,14 @@
<com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/keyguard_security_width"
+ android:layout_height="@dimen/keyguard_security_height"
androidprv:layout_childType="challenge"
androidprv:layout_centerWithinArea="0.55">
<com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
android:id="@+id/view_flipper"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingLeft="@dimen/keyguard_security_view_margin"
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index ed55e61..a3c8105 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -36,7 +36,8 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ androidprv:layout_childType="widgets">
<include layout="@layout/keyguard_widget_pager"
android:id="@+id/app_widget_container"
android:layout_width="match_parent"
@@ -52,21 +53,18 @@
<com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/keyguard_security_height"
androidprv:layout_childType="challenge"
- android:layout_marginLeft="@dimen/kg_edge_swipe_region_size"
- android:layout_marginRight="@dimen/kg_edge_swipe_region_size"
android:background="@drawable/kg_bouncer_bg_white"
+ android:padding="0dp"
android:gravity="bottom|center_horizontal">
<com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
android:id="@+id/view_flipper"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingLeft="@dimen/keyguard_security_view_margin"
android:paddingTop="@dimen/keyguard_security_view_margin"
- android:paddingRight="@dimen/keyguard_security_view_margin"
android:gravity="center">
</com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
</com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml
index 3b29db8..7fd370b 100644
--- a/core/res/res/layout-port/keyguard_widget_pager.xml
+++ b/core/res/res/layout-port/keyguard_widget_pager.xml
@@ -25,7 +25,7 @@
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:paddingTop="25dp"
- android:paddingBottom="64dp"
+ android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
android:clipChildren="false"
android:clipToPadding="false"
androidprv:pageSpacing="10dp">
diff --git a/core/res/res/layout/keyguard_face_unlock_view.xml b/core/res/res/layout/keyguard_face_unlock_view.xml
index ae7984c..976d0c6 100644
--- a/core/res/res/layout/keyguard_face_unlock_view.xml
+++ b/core/res/res/layout/keyguard_face_unlock_view.xml
@@ -30,10 +30,10 @@
android:layout_height="wrap_content"
/>
- <RelativeLayout
+ <com.android.internal.widget.FaceUnlockView
android:id="@+id/face_unlock_area_view"
android:layout_width="match_parent"
- android:layout_height="@*android:dimen/face_unlock_height"
+ android:layout_height="0dp"
android:background="@*android:drawable/intro_bg"
android:gravity="center"
android:layout_weight="1">
@@ -55,8 +55,7 @@
android:background="#00000000"
android:src="@*android:drawable/ic_facial_backup"
/>
-
- </RelativeLayout>
+ </com.android.internal.widget.FaceUnlockView>
<include layout="@layout/keyguard_emergency_carrier_area"
android:id="@+id/keyguard_selector_fade_container"
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
index a184415..b6faf5b 100644
--- a/core/res/res/layout/keyguard_password_view.xml
+++ b/core/res/res/layout/keyguard_password_view.xml
@@ -22,73 +22,61 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center">
+ android:gravity="bottom"
+ >
- <FrameLayout
+ <Space
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1">
+ android:layout_weight="1"
+ />
- <include layout="@layout/keyguard_message_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
+ <include layout="@layout/keyguard_message_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_gravity="center">
+ <!-- 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_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:background="#70000000"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ <EditText android:id="@+id/passwordEntry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+ android:singleLine="true"
+ android:textStyle="normal"
+ android:inputType="textPassword"
+ android:textSize="36sp"
+ android:background="@null"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="#ffffffff"
+ android:imeOptions="flagForceAscii|actionDone"
+ />
- <!-- 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_gravity="center_vertical|fill_horizontal"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="horizontal"
- android:background="#70000000"
- android:layout_marginStart="4dip"
- android:layout_marginEnd="4dip">
+ <ImageView android:id="@+id/switch_ime_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@*android:drawable/ic_lockscreen_ime"
+ android:clickable="true"
+ android:padding="8dip"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
- <EditText android:id="@+id/passwordEntry"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center_horizontal"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
- android:singleLine="true"
- android:textStyle="normal"
- android:inputType="textPassword"
- android:textSize="36sp"
- android:background="@null"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="#ffffffff"
- android:imeOptions="flagForceAscii|actionDone"
- />
-
- <ImageView android:id="@+id/switch_ime_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@*android:drawable/ic_lockscreen_ime"
- android:clickable="true"
- android:padding="8dip"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackground"
- android:visibility="gone"
- />
-
- </LinearLayout>
- </LinearLayout>
</LinearLayout>
- </FrameLayout>
+
<include layout="@layout/keyguard_emergency_carrier_area"
android:id="@+id/keyguard_selector_fade_container"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
index d62570b..2529196 100644
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ b/core/res/res/layout/keyguard_pin_view.xml
@@ -21,8 +21,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_pin_view"
- android:layout_width="350dp"
- android:layout_height="350dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
>
<include layout="@layout/keyguard_message_area"
@@ -35,7 +35,7 @@
android:orientation="horizontal"
android:layout_weight="1"
>
- <TextView android:id="@+id/passwordEntry"
+ <TextView android:id="@+id/pinEntry"
android:editable="true"
android:layout_width="0dip"
android:layout_height="match_parent"
@@ -59,6 +59,7 @@
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@string/keyboardview_keycode_delete"
/>
</LinearLayout>
<View
@@ -78,7 +79,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="1"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -87,7 +88,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="2"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -96,7 +97,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="3"
/>
</LinearLayout>
@@ -112,7 +113,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="4"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -121,7 +122,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="5"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -130,7 +131,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="6"
/>
</LinearLayout>
@@ -146,7 +147,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="7"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -155,7 +156,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="8"
/>
<view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -164,7 +165,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="9"
/>
</LinearLayout>
@@ -185,7 +186,7 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- androidprv:textView="@+id/passwordEntry"
+ androidprv:textView="@+id/pinEntry"
androidprv:digit="0"
/>
<ImageButton
@@ -196,6 +197,7 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/sym_keyboard_return_holo"
+ android:contentDescription="@string/keyboardview_keycode_enter"
/>
</LinearLayout>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 07f62ed..36f2628 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -50,4 +50,10 @@
<!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
<dimen name="kg_secure_padding_height">0dp</dimen>
+ <!-- Top padding for the widget pager -->
+ <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+ <!-- Bottom padding for the widget pager -->
+ <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+
</resources>
diff --git a/core/res/res/values-sw380dp/dimens.xml b/core/res/res/values-sw380dp/dimens.xml
new file mode 100644
index 0000000..fc0e85d
--- /dev/null
+++ b/core/res/res/values-sw380dp/dimens.xml
@@ -0,0 +1,23 @@
+<?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.
+*/
+-->
+
+<resources>
+ <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_width">340dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 0d01df4..52c230b 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -98,10 +98,10 @@
<dimen name="kg_widget_pager_horizontal_padding">24dp</dimen>
<!-- Top padding for the widget pager -->
- <dimen name="kg_widget_pager_top_padding">24dp</dimen>
+ <dimen name="kg_widget_pager_top_padding">0dp</dimen>
<!-- Bottom padding for the widget pager -->
- <dimen name="kg_widget_pager_bottom_padding">16dp</dimen>
+ <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
<!-- Top margin for the runway lights. We add a negative margin in large
devices to account for the widget pager padding -->
diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml
index d6d2b66..ccdb4be 100644
--- a/core/res/res/values-sw720dp/dimens.xml
+++ b/core/res/res/values-sw720dp/dimens.xml
@@ -91,10 +91,10 @@
<dimen name="kg_widget_pager_horizontal_padding">80dp</dimen>
<!-- Top padding for the widget pager -->
- <dimen name="kg_widget_pager_top_padding">32dp</dimen>
+ <dimen name="kg_widget_pager_top_padding">0dp</dimen>
<!-- Bottom padding for the widget pager -->
- <dimen name="kg_widget_pager_bottom_padding">36dp</dimen>
+ <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
<!-- Top margin for the runway lights. We add a negative margin in large
devices to account for the widget pager padding -->
@@ -112,4 +112,9 @@
<!-- Size of the text under the avator on the multiuser lockscreen. -->
<dimen name="keyguard_avatar_name_size">12sp</dimen>
+ <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_width">420dp</dimen>
+
+ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_height">420dp</dimen>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6505ad0..186c8b3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5816,6 +5816,8 @@
<!-- Scrim. This will block access to child views that
come before it in the child list in bouncer mode. -->
<enum name="scrim" value="4" />
+ <!-- The home for widgets. All widgets will be descendents of this. -->
+ <enum name="widgets" value="5" />
</attr>
<declare-styleable name="SlidingChallengeLayout">
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b830e79..4966b97 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -294,7 +294,7 @@
<dimen name="kg_widget_pager_top_padding">0dp</dimen>
<!-- Bottom padding for the widget pager -->
- <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+ <dimen name="kg_widget_pager_bottom_padding">64dp</dimen>
<!-- Top margin for the runway lights. We add a negative margin in large
devices to account for the widget pager padding -->
@@ -303,6 +303,12 @@
<!-- Touch slop for the global toggle accessibility gesture -->
<dimen name="accessibility_touch_slop">80dip</dimen>
+ <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_width">320dp</dimen>
+
+ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_height">400dp</dimen>
+
<!-- Margin around the various security views -->
<dimen name="keyguard_security_view_margin">8dp</dimen>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index d1df2a4..053fc85 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -18,7 +18,7 @@
-->
<resources>
<integer name="kg_carousel_angle">75</integer>
- <integer name="kg_security_flip_duration">75</integer>
- <integer name="kg_security_fade_duration">75</integer>
+ <integer name="kg_security_flip_duration">100</integer>
+ <integer name="kg_security_fade_duration">100</integer>
<integer name="kg_glowpad_rotation_offset">0</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 159eec1..51d6429 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2065,6 +2065,15 @@
<!-- 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 />
@@ -2276,14 +2285,12 @@
<string name="keyguard_accessibility_add_widget">Add widget.</string>
<!-- Accessibility description of the empty sidget slot (place holder for a new widget). [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_widget_empty_slot">Empty</string>
- <!-- Accessibility description of the unlock area. [CHAR_LIMIT=none] -->
- <string name="keyguard_accessibility_unlock_area">Unlock area.</string>
<!-- Accessibility description of the event of expanding an unlock area. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_unlock_area_expanded">Unlock area expanded.</string>
<!-- Accessibility description of the event of collapsing an unlock area. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_unlock_area_collapsed">Unlock area collapsed.</string>
<!-- Accessibility description of a lock screen widget. [CHAR_LIMIT=none] -->
- <string name="keyguard_accessibility_widget">%1$s widget.</string>
+ <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
<!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_user_selector">User selector</string>
<!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
@@ -2292,6 +2299,28 @@
<string name="keyguard_accessibility_camera">Camera</string>
<!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
<string name="keygaurd_accessibility_media_controls">Media controls</string>
+ <!-- Accessibility description of widget reordering start. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_widget_reorder_start">Widget reordering started.</string>
+ <!-- Accessibility description of widget reordering end. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_widget_reorder_end">Widget reordering ended.</string>
+ <!-- Accessibility description of the a widget deletion event. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_widget_deleted">Widget <xliff:g id="widget_index">%1$s</xliff:g> deleted.</string>
+ <!-- Accessibility description of the button to expand the lock area. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_expand_lock_area">Expand unlock area.</string>
+ <!-- Accessibility description of the slide unlock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_slide_unlock">Slide unlock.</string>
+ <!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
+ <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_face_unlock">Face unlock.</string>
+ <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string>
+ <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_password_unlock">Password unlock.</string>
+ <!-- Accessibility description of the unlock pattern area. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_pattern_area">Pattern area.</string>
+ <!-- Accessibility description of the unlock slide area. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_slide_area">Slide area.</string>
<!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
<!-- Label for "switch to symbols" key. Must be short to fit on key! -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7ebf7e7..5af60c8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,6 +479,9 @@
<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" />
<java-symbol type="string" name="enable_accessibility_canceled" />
<java-symbol type="string" name="eventTypeAnniversary" />
@@ -1269,6 +1272,7 @@
<java-symbol type="id" name="option3" />
<java-symbol type="id" name="password" />
<java-symbol type="id" name="passwordEntry" />
+ <java-symbol type="id" name="pinEntry" />
<java-symbol type="id" name="pinDel" />
<java-symbol type="id" name="pinDisplay" />
<java-symbol type="id" name="owner_info" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 1bbc7df..5db7ffc 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -74,4 +74,5 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INJECT_EVENTS" />
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 561e33e..245f537 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -65,6 +65,8 @@
public static final long LONG_TIMEOUT = 50 * 1000;
// 2 minutes timer between wifi stop and start
public static final long WIFI_STOP_START_INTERVAL = 2 * 60 * 1000;
+ // Set ping test timer to be 3 minutes
+ public static final long PING_TIMER = 3 * 60 *1000;
public static final int SUCCESS = 0; // for Wifi tethering state change
public static final int FAILURE = 1;
public static final int INIT = -1;
@@ -517,37 +519,36 @@
* @return true if the ping test is successful, false otherwise.
*/
public boolean pingTest(String[] pingServerList) {
- boolean result = false;
String[] hostList = {"www.google.com", "www.yahoo.com",
"www.bing.com", "www.facebook.com", "www.ask.com"};
if (pingServerList != null) {
hostList = pingServerList;
}
- try {
- // assume the chance that all servers are down is very small
- for (int i = 0; i < hostList.length; i++ ) {
- String host = hostList[i];
- log("Start ping test, ping " + host);
- Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
- int status = p.waitFor();
- if (status == 0) {
- // if any of the ping test is successful, return true
- result = true;
- break;
- } else {
- result = false;
- log("ping " + host + " failed.");
+
+ long startTime = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
+ try {
+ // assume the chance that all servers are down is very small
+ for (int i = 0; i < hostList.length; i++ ) {
+ String host = hostList[i];
+ log("Start ping test, ping " + host);
+ Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
+ int status = p.waitFor();
+ if (status == 0) {
+ // if any of the ping test is successful, return true
+ return true;
+ }
}
+ } catch (UnknownHostException e) {
+ log("Ping test Fail: Unknown Host");
+ } catch (IOException e) {
+ log("Ping test Fail: IOException");
+ } catch (InterruptedException e) {
+ log("Ping test Fail: InterruptedException");
}
- } catch (UnknownHostException e) {
- log("Ping test Fail: Unknown Host");
- } catch (IOException e) {
- log("Ping test Fail: IOException");
- } catch (InterruptedException e) {
- log("Ping test Fail: InterruptedException");
}
- log("return");
- return result;
+ // ping test timeout
+ return false;
}
/**
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 79d928c..7bfb594 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -28,6 +28,7 @@
import android.os.Environment;
import android.os.PowerManager;
import android.provider.Settings;
+import android.view.KeyEvent;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -289,6 +290,11 @@
// Turn screen on again
mAct.turnScreenOn();
+ // Wait for 2 seconds for the lock screen
+ sleep(2 * 1000, "wait 2 seconds for lock screen");
+ // Disable lock screen by inject menu key event
+ mRunner.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+
// Measure the time for Wi-Fi to get connected
long startTime = System.currentTimeMillis();
assertTrue("Wait for Wi-Fi enable timeout after wake up",
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 463343d..a3538a9 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -15,7 +15,7 @@
<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
<li><a href="#pricing">10. Set prices for your apps</a></li>
<li><a href="#localize">11. Start localization early</a></li>
-<li><a href="#localize">12. Prepare promotional graphics</a></li>
+<li><a href="#graphics">12. Prepare promotional graphics</a></li>
<li><a href="#apk">13. Build the release-ready APK</a></li>
<li><a href="#product-page">14. Complete the product details</a></li>
<li><a href="#badges">15. Use Google Play badges</a></li>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 8374b10..0623a9e 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1191,6 +1191,11 @@
return;
}
+ if (mRadius > 0 || mRadiusArray != null) {
+ mOpaque = false;
+ return;
+ }
+
if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) {
mOpaque = false;
return;
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index e0e11be..791d3d0 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -22,7 +22,7 @@
/**
* Represents a geographical boundary, also known as a geofence.
*
- * <p>Currently only circular geofences are supported.
+ * <p>Currently only circular geofences are supported and they do not support altitude changes.
*/
public final class Geofence implements Parcelable {
/** @hide */
@@ -34,10 +34,10 @@
private final float mRadius;
/**
- * Create a horizontal, circular geofence.
+ * Create a circular geofence (on a flat, horizontal plane).
*
- * @param latitude latitude in degrees, between -90 and +90 inclusive
- * @param longitude longitude in degrees, between -180 and +180 inclusive
+ * @param latitude latitude in degrees
+ * @param longitude longitude in degrees
* @param radius radius in meters
* @return a new geofence
* @throws IllegalArgumentException if any parameters are out of range
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 59a5624..653e8d1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -811,6 +811,10 @@
/**
* Register for fused location updates using a LocationRequest and callback.
*
+ * <p>Upon a location update, the system delivers the new {@link Location} to the
+ * provided {@link LocationListener}, by calling its {@link
+ * LocationListener#onLocationChanged} method.</p>
+ *
* <p>The system will automatically select and enable the best providers
* to compute a location for your application. It may use only passive
* locations, or just a single location source, or it may fuse together
@@ -869,6 +873,10 @@
/**
* Register for fused location updates using a LocationRequest and a pending intent.
*
+ * <p>Upon a location update, the system delivers the new {@link Location} with your provided
+ * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
+ * in the intent's extras.</p>
+ *
* <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
*
* <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index 8e0061d..737e17f 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -33,8 +33,8 @@
* Criteria} class allows providers to be selected based on
* user-specified criteria.
*
- * @deprecated Use the {@link LocationRequest} class to request location
- * instead of enumerating providers.
+ * @deprecated Use the {@link Criteria} class to request location instead of
+ * enumerating providers.
*/
@Deprecated
public class LocationProvider {
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index e940c85..8fdde92 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -41,8 +41,7 @@
android:fadingEdge="horizontal"
android:scrollbars="none"
android:layout_gravity="right"
- android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
- android:importantForAccessibility="no">
+ android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index 12599f8..7335f86 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -45,8 +45,7 @@
android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
android:layout_gravity="bottom|left"
android:clipToPadding="false"
- android:clipChildren="false"
- android:importantForAccessibility="no">
+ android:clipChildren="false">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index 8afed22..3951bba 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -49,8 +49,7 @@
android:fadingEdgeLength="20dip"
android:layout_gravity="bottom|left"
android:clipToPadding="false"
- android:clipChildren="false"
- android:importantForAccessibility="no">
+ android:clipChildren="false">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c34ca3e..7f7a51c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -174,7 +174,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skærmen er nu låst i stående retning."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Dagdrømme"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Oplader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d5af0cd..d619de1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -176,7 +176,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Activar Daydreams"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Activar protector"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avión"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e8bc08d..19de9b6 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -174,7 +174,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Suspender"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Salvapantallas"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a12ccf0..babbcce 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -176,7 +176,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Écran de veille interactif"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a05aa8f..c454bb1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -174,7 +174,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Śnij na jawie"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Wygaszacz ekranu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1ca085c..1b8370b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -174,7 +174,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"O ecrã está bloqueado na orientação horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"O ecrã está bloqueado na orientação vertical."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Sonho"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avião"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"A carregar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fba3da5..7e2d030 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -172,7 +172,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrini imefungwa sasa katika uelekezo wa mandhari."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrini imefungwa katika uelekeo wa picha."</string>
<string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
- <string name="start_dreams" msgid="7219575858348719790">"Ndoto ya mchana"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Hali Tulivu"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modi ya ndege"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Inachaji, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 599b7e2..cc9c601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -202,21 +202,18 @@
Log.e(TAG, "Couldn't get user info", e);
}
final int userId = userInfo.id;
+ final String userName = userInfo.name;
final Context context = currentUserContext;
mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
@Override
protected Pair<String, Drawable> doInBackground(Void... params) {
- final Cursor cursor = context.getContentResolver().query(
- Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
- null, null, null);
final UserManager um =
(UserManager) mContext.getSystemService(Context.USER_SERVICE);
// Fall back to the UserManager nickname if we can't read the name from the local
// profile below.
- String nickName = um.getUserName();
- String name = nickName;
+ String name = userName;
Drawable avatar = null;
Bitmap rawAvatar = um.getUserIcon(userId);
if (rawAvatar != null) {
@@ -225,17 +222,23 @@
avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
}
- // Try and read the display name from the local profile
- if (cursor != null) {
- try {
- if (cursor.moveToFirst()) {
- name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+ // If it's a single-user device, get the profile name, since the nickname is not
+ // usually valid
+ if (um.getUsers().size() <= 1) {
+ // Try and read the display name from the local profile
+ final Cursor cursor = context.getContentResolver().query(
+ Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
+ null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+ }
+ } finally {
+ cursor.close();
}
- } finally {
- cursor.close();
}
}
-
return new Pair<String, Drawable>(name, avatar);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index fefd4fb..de028a4 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -412,7 +412,17 @@
boolean mForceStatusBar;
boolean mForceStatusBarFromKeyguard;
boolean mHideLockScreen;
- boolean mDismissKeyguard;
+
+ // States of keyguard dismiss.
+ private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
+ private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
+ private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
+ int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+
+ /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
+ * be done once per window. */
+ private WindowState mWinDismissingKeyguard;
+
boolean mShowingLockscreen;
boolean mShowingDream;
boolean mDreamingLockscreen;
@@ -2921,6 +2931,7 @@
}
/** {@inheritDoc} */
+ @Override
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mForceStatusBar = false;
@@ -2928,12 +2939,13 @@
mHideLockScreen = false;
mAllowLockscreenWhenOn = false;
- mDismissKeyguard = false;
+ mDismissKeyguard = DISMISS_KEYGUARD_NONE;
mShowingLockscreen = false;
mShowingDream = false;
}
/** {@inheritDoc} */
+ @Override
public void applyPostLayoutPolicyLw(WindowState win,
WindowManager.LayoutParams attrs) {
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
@@ -2953,10 +2965,11 @@
boolean applyWindow = attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW;
if (attrs.type == TYPE_DREAM) {
- mShowingDream = true;
- if (!mDreamingLockscreen) {
- applyWindow = true;
- } else if (win.isVisibleLw() && win.hasDrawnLw()) {
+ // If the lockscreen was showing when the dream started then wait
+ // for the dream to draw before hiding the lockscreen.
+ if (!mDreamingLockscreen
+ || (win.isVisibleLw() && win.hasDrawnLw())) {
+ mShowingDream = true;
applyWindow = true;
}
}
@@ -2971,9 +2984,12 @@
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
}
- if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
+ if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
+ && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
- mDismissKeyguard = true;
+ mDismissKeyguard = mWinDismissingKeyguard == win ?
+ DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
+ mWinDismissingKeyguard = win;
mForceStatusBarFromKeyguard = false;
}
if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
@@ -2984,6 +3000,7 @@
}
/** {@inheritDoc} */
+ @Override
public int finishPostLayoutPolicyLw() {
int changes = 0;
boolean topIsFullscreen = false;
@@ -2992,8 +3009,10 @@
? mTopFullscreenOpaqueWindowState.getAttrs()
: null;
- // If we are not currently showing a dream, then update the lockscreen
- // state that will apply if a dream is shown next time.
+ // If we are not currently showing a dream then remember the current
+ // lockscreen state. We will use this to determine whether the dream
+ // started while the lockscreen was showing and remember this state
+ // while the dream is showing.
if (!mShowingDream) {
mDreamingLockscreen = mShowingLockscreen;
}
@@ -3023,7 +3042,9 @@
if (mStatusBar.hideLw(true)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT;
- mHandler.post(new Runnable() { public void run() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
try {
IStatusBarService statusbar = getStatusBarService();
if (statusbar != null) {
@@ -3051,7 +3072,7 @@
if (mKeyguard != null) {
if (localLOGV) Log.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
+ mHideLockScreen);
- if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
+ if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardMediator.isSecure()) {
if (mKeyguard.hideLw(true)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT
| FINISH_LAYOUT_REDO_CONFIG
@@ -3059,6 +3080,7 @@
}
if (mKeyguardMediator.isShowing()) {
mHandler.post(new Runnable() {
+ @Override
public void run() {
mKeyguardMediator.keyguardDone(false, false);
}
@@ -3071,7 +3093,25 @@
| FINISH_LAYOUT_REDO_WALLPAPER;
}
mKeyguardMediator.setHidden(true);
+ } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
+ // This is the case of keyguard isSecure() and not mHideLockScreen.
+ if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
+ // Only launch the next keyguard unlock window once per window.
+ if (mKeyguard.showLw(true)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT
+ | FINISH_LAYOUT_REDO_CONFIG
+ | FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ mKeyguardMediator.setHidden(false);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardMediator.dismiss();
+ }
+ });
+ }
} else {
+ mWinDismissingKeyguard = null;
if (mKeyguard.showLw(true)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT
| FINISH_LAYOUT_REDO_CONFIG
@@ -4549,6 +4589,7 @@
pw.print(" mForceStatusBarFromKeyguard=");
pw.println(mForceStatusBarFromKeyguard);
pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
+ pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
pw.print(" mHomePressed="); pw.println(mHomePressed);
pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
index b38a9ed..3dd0a8f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -21,12 +21,15 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Point;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
@@ -47,10 +50,11 @@
private final Handler mHandler = new Handler();
private final KeyguardActivityLauncher mActivityLauncher;
private final Callbacks mCallbacks;
+ private final WindowManager mWindowManager;
+ private final Point mRenderedSize = new Point();
private View mWidgetView;
private long mLaunchCameraStart;
- private boolean mRendered;
private boolean mActive;
private boolean mChallengeActive;
private boolean mTransitioning;
@@ -81,6 +85,7 @@
mCallbacks = callbacks;
mActivityLauncher = activityLauncher;
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
public static CameraWidgetFrame create(Context context, Callbacks callbacks,
@@ -141,16 +146,22 @@
}
public void render() {
- if (mRendered) return;
-
try {
int width = getRootView().getWidth();
int height = getRootView().getHeight();
- if (DEBUG) Log.d(TAG, String.format("render [%sx%s] %s",
- width, height, Integer.toHexString(hashCode())));
+ if (mRenderedSize.x == width && mRenderedSize.y == height) {
+ if (DEBUG) Log.d(TAG, String.format("already rendered at size=%sx%s",
+ width, height));
+ return;
+ }
if (width == 0 || height == 0) {
return;
}
+ if (DEBUG) Log.d(TAG, String.format("render size=%sx%s instance=%s at %s",
+ width, height,
+ Integer.toHexString(hashCode()),
+ SystemClock.uptimeMillis()));
+
Bitmap offscreen = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(offscreen);
mWidgetView.measure(
@@ -159,7 +170,7 @@
mWidgetView.layout(0, 0, width, height);
mWidgetView.draw(c);
((ImageView)getChildAt(0)).setImageBitmap(offscreen);
- mRendered = true;
+ mRenderedSize.set(width, height);
} catch (Throwable t) {
Log.w(TAG, "Error rendering camera widget", t);
removeAllViews();
@@ -200,6 +211,7 @@
scaleX, scaleY,
startCenter, finishCenter));
+ enableWindowExitAnimation(false);
animate()
.scaleX(scale)
.scaleY(scale)
@@ -305,11 +317,27 @@
setScaleX(1);
setScaleY(1);
setTranslationY(0);
+ enableWindowExitAnimation(true);
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
+ w, h, oldw, oldh, SystemClock.uptimeMillis()));
mHandler.post(mRenderRunnable);
+ super.onSizeChanged(w, h, oldw, oldh);
+ }
+
+ private void enableWindowExitAnimation(boolean isEnabled) {
+ View root = getRootView();
+ ViewGroup.LayoutParams lp = root.getLayoutParams();
+ if (!(lp instanceof WindowManager.LayoutParams))
+ return;
+ WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
+ int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
+ if (newWindowAnimations != wlp.windowAnimations) {
+ wlp.windowAnimations = newWindowAnimations;
+ mWindowManager.updateViewLayout(root, wlp);
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
index cae598c..faf0ca0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
@@ -151,13 +151,6 @@
}
boolean mWasRunning = mIsRunning;
- try {
- if (mService != null) {
- mService.makeInvisible();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Caught exception making Face Unlock invisible: " + e.toString());
- }
stopUi();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
index 9c21830..db36bcc 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
@@ -87,16 +87,20 @@
}
}
+ protected abstract int getPasswordTextViewId();
protected abstract void resetState();
@Override
protected void onFinishInflate() {
mLockPatternUtils = new LockPatternUtils(mContext);
- mPasswordEntry = (TextView) findViewById(R.id.passwordEntry);
+ mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
mPasswordEntry.setOnEditorActionListener(this);
mPasswordEntry.addTextChangedListener(this);
+ // Set selected property on so the view can send accessibility events.
+ mPasswordEntry.setSelected(true);
+
// Poke the wakelock any time the text is selected or modified
mPasswordEntry.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 3a01e64..3b2ded2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -25,19 +25,22 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+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;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -48,13 +51,13 @@
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.widget.RemoteViews.OnClickHandler;
-import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.internal.widget.LockPatternUtils;
import java.io.File;
+import java.util.ArrayList;
import java.util.List;
public class KeyguardHostView extends KeyguardViewBase {
@@ -66,11 +69,6 @@
// also referenced in SecuritySettings.java
static final int APPWIDGET_HOST_ID = 0x4B455947;
- // transport control states
- private static final int TRANSPORT_GONE = 0;
- private static final int TRANSPORT_INVISIBLE = 1;
- private static final int TRANSPORT_VISIBLE = 2;
-
private AppWidgetHost mAppWidgetHost;
private KeyguardWidgetPager mAppWidgetContainer;
private KeyguardSecurityViewFlipper mSecurityViewContainer;
@@ -90,7 +88,6 @@
private KeyguardViewStateManager mViewStateManager;
private Rect mTempRect = new Rect();
- private int mTransportState = TRANSPORT_GONE;
/*package*/ interface TransportCallback {
void onListenerDetached();
@@ -144,7 +141,7 @@
private int getWidgetPosition(int id) {
final int children = mAppWidgetContainer.getChildCount();
for (int i = 0; i < children; i++) {
- if (mAppWidgetContainer.getChildAt(i).getId() == id) {
+ if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) {
return i;
}
}
@@ -153,6 +150,8 @@
@Override
protected void onFinishInflate() {
+ mViewStateManager = new KeyguardViewStateManager();
+
// Grab instances of and make any necessary changes to the main layouts. Create
// view state manager and wire up necessary listeners / callbacks.
mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
@@ -162,8 +161,8 @@
addDefaultWidgets();
addWidgetsFromSettings();
+ mSwitchPageRunnable.run();
- mViewStateManager = new KeyguardViewStateManager();
SlidingChallengeLayout slider =
(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
if (slider != null) {
@@ -217,7 +216,6 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mAppWidgetHost.startListening();
- post(mSwitchPageRunnable);
}
@Override
@@ -676,13 +674,10 @@
// Find and show this child.
final int childCount = mSecurityViewContainer.getChildCount();
- // Do flip animation to the next screen
- if (false) {
- mSecurityViewContainer.setInAnimation(
- AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_in));
- mSecurityViewContainer.setOutAnimation(
- AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_out));
- }
+ mSecurityViewContainer.setInAnimation(
+ AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in));
+ mSecurityViewContainer.setOutAnimation(
+ AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out));
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
for (int i = 0; i < childCount; i++) {
if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
@@ -864,7 +859,8 @@
@Override
LockPatternUtils getLockPatternUtils() {
return mLockPatternUtils;
- }};
+ }
+ };
private void addDefaultWidgets() {
LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -888,14 +884,22 @@
@Override
public void run() {
- Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_CLEAR_TOP
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- mContext.startActivityAsUser(intent,
- new UserHandle(UserHandle.USER_CURRENT));
+ 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);
}
});
mCallback.dismiss(false);
@@ -906,6 +910,85 @@
initializeTransportControl();
}
+ private void launchPickActivityIntent(int defaultLabelId, int defaultIconId,
+ ComponentName defaultComponentName, String defaultTag) {
+ // Create intent to pick widget
+ Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
+
+ int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+ if (appWidgetId != -1) {
+ pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
+ 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
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ mContext.startActivityAsUser(pickIntent,
+ new UserHandle(UserHandle.USER_CURRENT));
+ } else {
+ Log.e(TAG, "Unable to allocate an AppWidget id in lock screen");
+ }
+ }
+
+ private Intent getBaseIntent() {
+ Intent baseIntent = new Intent(Intent.ACTION_MAIN, null);
+ baseIntent.addCategory(Intent.CATEGORY_DEFAULT);
+
+ Bundle options = new Bundle();
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+ AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
+ baseIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+ return baseIntent;
+ }
+
+ private void removeTransportFromWidgetPager() {
+ int page = getWidgetPosition(R.id.keyguard_transport_control);
+ if (page != -1) {
+ mAppWidgetContainer.removeWidget(mTransportControl);
+
+ // XXX keep view attached so we still get show/hide events from AudioManager
+ KeyguardHostView.this.addView(mTransportControl);
+ mTransportControl.setVisibility(View.GONE);
+ mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
+ mTransportControl.post(mSwitchPageRunnable);
+ }
+ }
+
+ private void addTransportToWidgetPager() {
+ if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
+ KeyguardHostView.this.removeView(mTransportControl);
+ // insert to left of camera if it exists, otherwise after right-most widget
+ int lastWidget = mAppWidgetContainer.getChildCount() - 1;
+ int position = 0; // handle no widget case
+ if (lastWidget >= 0) {
+ position = isCameraPage(lastWidget) ? lastWidget : lastWidget + 1;
+ }
+ mAppWidgetContainer.addWidget(mTransportControl, position);
+ mTransportControl.setVisibility(View.VISIBLE);
+ }
+ }
+
private void initializeTransportControl() {
mTransportControl =
(KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
@@ -917,24 +1000,14 @@
mTransportControl.setKeyguardCallback(new TransportCallback() {
@Override
public void onListenerDetached() {
- int page = getWidgetPosition(R.id.keyguard_transport_control);
- if (page != -1) {
- mAppWidgetContainer.removeView(mTransportControl);
- // XXX keep view attached so we still get show/hide events from AudioManager
- KeyguardHostView.this.addView(mTransportControl);
- mTransportControl.setVisibility(View.GONE);
- mTransportState = TRANSPORT_GONE;
- mTransportControl.post(mSwitchPageRunnable);
- }
+ removeTransportFromWidgetPager();
+ mTransportControl.post(mSwitchPageRunnable);
}
@Override
public void onListenerAttached() {
- if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
- KeyguardHostView.this.removeView(mTransportControl);
- mAppWidgetContainer.addView(mTransportControl, 0);
- mTransportControl.setVisibility(View.VISIBLE);
- }
+ // Transport will be added when playstate changes...
+ mTransportControl.post(mSwitchPageRunnable);
}
@Override
@@ -1027,7 +1100,7 @@
saveStickyWidgetIndex();
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
- ss.transportState = mTransportState;
+ ss.transportState = mViewStateManager.getTransportState();
return ss;
}
@@ -1040,7 +1113,7 @@
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
- mTransportState = ss.transportState;
+ mViewStateManager.setTransportState(ss.transportState);
post(mSwitchPageRunnable);
}
@@ -1054,12 +1127,14 @@
}
private void showAppropriateWidgetPage() {
- boolean isMusicPlaying =
- mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE;
+ int state = mViewStateManager.getTransportState();
+ boolean isMusicPlaying = mTransportControl.isMusicPlaying()
+ || state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
if (isMusicPlaying) {
- mTransportState = TRANSPORT_VISIBLE;
- } else if (mTransportState == TRANSPORT_VISIBLE) {
- mTransportState = TRANSPORT_INVISIBLE;
+ mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
+ addTransportToWidgetPager();
+ } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
+ mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
}
int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
mAppWidgetContainer.setCurrentPage(pageToShow);
@@ -1081,7 +1156,7 @@
// if music playing, show transport
if (isMusicPlaying) {
if (DEBUG) Log.d(TAG, "Music playing, show transport");
- return mAppWidgetContainer.indexOfChild(mTransportControl);
+ return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
}
// if we have a valid sticky widget, show it
@@ -1119,6 +1194,10 @@
}
private void enableUserSelectorIfNecessary() {
+ if (!UserManager.supportsMultipleUsers()) {
+ return; // device doesn't support multi-user mode
+ }
+
// if there are multiple users, we need to enable to multi-user switcher
UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
List<UserInfo> users = mUm.getUsers(true);
@@ -1201,4 +1280,10 @@
return false;
}
+ /**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ */
+ public void dismiss() {
+ showNextSecurityScreenOrFinish(false);
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index ca78cf9..5e331e1 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -16,6 +16,9 @@
package com.android.internal.policy.impl.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
@@ -39,11 +42,15 @@
static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
static final int SECURITY_MESSAGE_DURATION = 5000;
- static final String SEPARATOR = " ";
+ protected static final int FADE_DURATION = 750;
+ static final String SEPARATOR = " ";
// are we showing battery information?
boolean mShowingBatteryInfo = false;
+ // is the bouncer up?
+ boolean mShowingBouncer = false;
+
// last known plugged in state
boolean mPluggedIn = false;
@@ -68,7 +75,11 @@
public void run() {
mMessage = null;
mShowingMessage = false;
- update();
+ if (mShowingBouncer) {
+ hideMessage(FADE_DURATION, true);
+ } else {
+ update();
+ }
}
};
@@ -103,6 +114,18 @@
}
@Override
+ public void showBouncer(int duration) {
+ mMessageArea.hideMessage(duration, false);
+ mMessageArea.mShowingBouncer = true;
+ }
+
+ @Override
+ public void hideBouncer(int duration) {
+ mMessageArea.showMessage(duration);
+ mMessageArea.mShowingBouncer = false;
+ }
+
+ @Override
public void setTimeout(int timeoutMs) {
mMessageArea.mTimeout = timeoutMs;
}
@@ -139,6 +162,7 @@
}
public void securityMessageChanged() {
+ setAlpha(1f);
mShowingMessage = true;
update();
mHandler.removeCallbacks(mClearMessageRunnable);
@@ -212,4 +236,23 @@
return string;
}
+ private void hideMessage(int duration, boolean thenUpdate) {
+ Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f);
+ anim.setDuration(duration);
+ if (thenUpdate) {
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ update();
+ }
+ });
+ }
+ anim.start();
+ }
+
+ private void showMessage(int duration) {
+ Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f);
+ anim.setDuration(duration);
+ anim.start();
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
index bea9aec..1255712 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
@@ -47,6 +47,11 @@
}
@Override
+ protected int getPasswordTextViewId() {
+ return R.id.pinEntry;
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -59,6 +64,7 @@
verifyPasswordAndUnlock();
}
});
+ ok.setOnHoverListener(new NumPadKey.LiftToActivateListener(getContext()));
}
// The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index b6334f0..b35450c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -60,6 +60,11 @@
}
@Override
+ protected int getPasswordTextViewId() {
+ return R.id.passwordEntry;
+ }
+
+ @Override
public boolean needsInput() {
return true;
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
index f6a90c5..04ab0a2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
@@ -1,11 +1,20 @@
package com.android.internal.policy.impl.keyguard;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
+import com.android.internal.R;
+
public class KeyguardSecurityContainer extends FrameLayout {
+ private float mBackgroundAlpha;
+ private Drawable mBackgroundDrawable;
+
public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -16,5 +25,44 @@
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ mBackgroundDrawable = context.getResources().getDrawable(R.drawable.kg_bouncer_bg_white);
+ }
+
+ public void setBackgroundAlpha(float alpha) {
+ if (Float.compare(mBackgroundAlpha, alpha) != 0) {
+ mBackgroundAlpha = alpha;
+ invalidate();
+ }
+ }
+
+ public float getBackgroundAlpha() {
+ return mBackgroundAlpha;
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (mBackgroundAlpha > 0.0f && mBackgroundDrawable != null) {
+ Drawable bg = mBackgroundDrawable;
+ bg.setAlpha((int) (mBackgroundAlpha * 255));
+ bg.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ bg.draw(canvas);
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ public void showBouncer(int duration) {
+ SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+ message.showBouncer(duration);
+ Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 1f);
+ anim.setDuration(duration);
+ anim.start();
+ }
+
+ public void hideBouncer(int duration) {
+ SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+ message.hideBouncer(duration);
+ Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 0f);
+ anim.setDuration(duration);
+ anim.start();
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index b4bd6e9..7100f1c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -327,6 +327,14 @@
}
@Override
+ public void showBouncer(int duration) {
+ }
+
+ @Override
+ public void hideBouncer(int duration) {
+ }
+
+ @Override
public void setTimeout(int timeout_ms) {
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index 89f220a..d284602 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -40,6 +40,7 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -49,14 +50,13 @@
/**
* This is the widget responsible for showing music controls in keyguard.
*/
-public class KeyguardTransportControlView extends KeyguardWidgetFrame implements OnClickListener {
+public class KeyguardTransportControlView extends FrameLayout implements OnClickListener {
private static final int MSG_UPDATE_STATE = 100;
private static final int MSG_SET_METADATA = 101;
private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
private static final int MSG_SET_ARTWORK = 103;
private static final int MSG_SET_GENERATION_ID = 104;
- private static final int MAXDIM = 512;
private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
protected static final boolean DEBUG = false;
protected static final String TAG = "TransportControlView";
@@ -260,14 +260,6 @@
mAttached = false;
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-// int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
-// Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
-// mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
- }
-
class Metadata {
private String artist;
private String trackTitle;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 9fa14f5..b224c08 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -65,6 +65,7 @@
private FrameLayout mKeyguardHost;
private KeyguardHostView mKeyguardView;
+ private boolean mScreenOn = false;
private LockPatternUtils mLockPatternUtils;
public interface ShowListener {
@@ -302,6 +303,7 @@
public synchronized void onScreenTurnedOff() {
if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
+ mScreenOn = false;
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOff();
}
@@ -310,6 +312,7 @@
public synchronized void onScreenTurnedOn(
final KeyguardViewManager.ShowListener showListener) {
if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
+ mScreenOn = true;
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOn();
@@ -398,6 +401,15 @@
}
/**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ */
+ public synchronized void dismiss() {
+ if (mScreenOn) {
+ mKeyguardView.dismiss();
+ }
+ }
+
+ /**
* @return Whether the keyguard is showing
*/
public synchronized boolean isShowing() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index bc12e96..53cbb39 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -813,9 +813,7 @@
}
/**
- * Enable the keyguard if the settings are appropriate. Return true if all
- * work that will happen is done; returns false if the caller can wait for
- * the keyguard to be shown.
+ * Enable the keyguard if the settings are appropriate.
*/
private void doKeyguardLocked(Bundle options) {
// if another app is disabling us, don't show
@@ -867,6 +865,13 @@
}
/**
+ * Dismiss the keyguard through the security layers.
+ */
+ public void dismiss() {
+ mKeyguardViewManager.dismiss();
+ }
+
+ /**
* Send message to keyguard telling it to reset its state.
* @param options options about how to show the keyguard
* @see #handleReset()
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index 85245ba..c89e880 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -32,6 +32,13 @@
private static final int SCREEN_ON_RING_HINT_DELAY = 300;
Handler mMainQueue = new Handler(Looper.myLooper());
+ // transport control states
+ static final int TRANSPORT_GONE = 0;
+ static final int TRANSPORT_INVISIBLE = 1;
+ static final int TRANSPORT_VISIBLE = 2;
+
+ private int mTransportState = TRANSPORT_GONE;
+
int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
// Paged view state
@@ -58,6 +65,13 @@
return false;
}
+ public boolean isChallengeOverlapping() {
+ if (mChallengeLayout != null) {
+ return mChallengeLayout.isChallengeOverlapping();
+ }
+ return false;
+ }
+
public void setSecurityViewContainer(KeyguardSecurityView container) {
mKeyguardSecurityContainer = container;
}
@@ -79,6 +93,14 @@
mChallengeLayout.showBouncer();
}
+ public void fadeOutSecurity(int duration) {
+ ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
+ }
+
+ public void fadeInSecurity(int duration) {
+ ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
+ }
+
public void onPageSwitch(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.
@@ -207,4 +229,12 @@
mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
}
+
+ public void setTransportState(int state) {
+ mTransportState = state;
+ }
+
+ public int getTransportState() {
+ return mTransportState;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
index cf16ef2..2e83b42 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
@@ -15,9 +15,19 @@
*/
package com.android.internal.policy.impl.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
import com.android.internal.R;
@@ -26,6 +36,8 @@
private float mAdjacentPagesAngle;
private static float MAX_SCROLL_PROGRESS = 1.3f;
private static float CAMERA_DISTANCE = 10000;
+ protected AnimatorSet mChildrenTransformsAnimator;
+ float[] mTmpTransform = new float[3];
public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -51,10 +63,10 @@
float scrollProgress = getScrollProgress(screenCenter, child, index);
if (!isOverScrollChild(index, scrollProgress)) {
scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
- float alpha = 1 - Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
+ float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
return alpha;
} else {
- return 1f;
+ return 1.0f;
}
}
@@ -67,22 +79,22 @@
for (int i = 0; i < getChildCount(); i++) {
KeyguardWidgetFrame child = getWidgetPageAt(i);
if (child != null) {
- float alpha = getAlphaForPage(screenCenter, i);
- child.setBackgroundAlpha(alpha);
- child.setContentAlpha(alpha);
+ child.setBackgroundAlpha(getOutlineAlphaForPage(screenCenter, i));
+ child.setContentAlpha(getAlphaForPage(screenCenter, i));
}
}
}
-
}
@Override
protected void screenScrolled(int screenCenter) {
mScreenCenter = screenCenter;
updatePageAlphaValues(screenCenter);
+ if (isReordering(false)) return;
for (int i = 0; i < getChildCount(); i++) {
KeyguardWidgetFrame v = getWidgetPageAt(i);
float scrollProgress = getScrollProgress(screenCenter, v, i);
+ float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
if (v == mDragView || v == null) continue;
v.setCameraDistance(CAMERA_DISTANCE);
@@ -90,17 +102,15 @@
v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
} else {
- scrollProgress = getBoundedScrollProgress(screenCenter, v, i);
int width = v.getMeasuredWidth();
- float pivotX = (width / 2f) + scrollProgress * (width / 2f);
+ float pivotX = (width / 2f) + boundedProgress * (width / 2f);
float pivotY = v.getMeasuredHeight() / 2;
- float rotationY = - mAdjacentPagesAngle * scrollProgress;
+ float rotationY = - mAdjacentPagesAngle * boundedProgress;
v.setPivotX(pivotX);
v.setPivotY(pivotY);
v.setRotationY(rotationY);
v.setOverScrollAmount(0f, false);
}
-
float alpha = v.getAlpha();
// If the view has 0 alpha, we set it to be invisible so as to prevent
// it from accepting touches
@@ -111,4 +121,139 @@
}
}
}
+
+ void animatePagesToNeutral() {
+ if (mChildrenTransformsAnimator != null) {
+ mChildrenTransformsAnimator.cancel();
+ mChildrenTransformsAnimator = null;
+ }
+
+ int count = getChildCount();
+ PropertyValuesHolder alpha;
+ PropertyValuesHolder outlineAlpha;
+ PropertyValuesHolder rotationY;
+ ArrayList<Animator> anims = new ArrayList<Animator>();
+
+ for (int i = 0; i < count; i++) {
+ KeyguardWidgetFrame child = getWidgetPageAt(i);
+ boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+ if (!inVisibleRange) {
+ child.setRotationY(0f);
+ }
+ alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
+ outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
+ KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+ rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
+ ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
+ child.setVisibility(VISIBLE);
+ if (!inVisibleRange) {
+ a.setInterpolator(mSlowFadeInterpolator);
+ }
+ anims.add(a);
+ }
+
+ int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+ mChildrenTransformsAnimator = new AnimatorSet();
+ mChildrenTransformsAnimator.playTogether(anims);
+
+ mChildrenTransformsAnimator.setDuration(duration);
+ mChildrenTransformsAnimator.start();
+ }
+
+ private void getTransformForPage(int screenCenter, int index, float[] transform) {
+ View child = getChildAt(index);
+ float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
+ float rotationY = - mAdjacentPagesAngle * boundedProgress;
+ int width = child.getMeasuredWidth();
+ float pivotX = (width / 2f) + boundedProgress * (width / 2f);
+ float pivotY = child.getMeasuredHeight() / 2;
+
+ transform[0] = pivotX;
+ transform[1] = pivotY;
+ transform[2] = rotationY;
+ }
+
+ Interpolator mFastFadeInterpolator = new Interpolator() {
+ Interpolator mInternal = new DecelerateInterpolator(1.5f);
+ float mFactor = 2.5f;
+ @Override
+ public float getInterpolation(float input) {
+ return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
+ }
+ };
+
+ Interpolator mSlowFadeInterpolator = new Interpolator() {
+ Interpolator mInternal = new AccelerateInterpolator(1.5f);
+ float mFactor = 1.3f;
+ @Override
+ public float getInterpolation(float input) {
+ input -= (1 - 1 / mFactor);
+ input = mFactor * Math.max(input, 0f);
+ return mInternal.getInterpolation(input);
+ }
+ };
+
+ void animatePagesToCarousel() {
+ if (mChildrenTransformsAnimator != null) {
+ mChildrenTransformsAnimator.cancel();
+ mChildrenTransformsAnimator = null;
+ }
+
+ int count = getChildCount();
+ PropertyValuesHolder alpha;
+ PropertyValuesHolder outlineAlpha;
+ PropertyValuesHolder rotationY;
+ PropertyValuesHolder pivotX;
+ PropertyValuesHolder pivotY;
+ ArrayList<Animator> anims = new ArrayList<Animator>();
+
+ for (int i = 0; i < count; i++) {
+ KeyguardWidgetFrame child = getWidgetPageAt(i);
+ float finalAlpha = getAlphaForPage(mScreenCenter, i);
+ float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i);
+ getTransformForPage(mScreenCenter, i, mTmpTransform);
+
+ boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+
+ ObjectAnimator a;
+ alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
+ outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
+ pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
+ pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
+ rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
+
+ if (inVisibleRange) {
+ // for the central pages we animate into a rotated state
+ a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
+ pivotX, pivotY, rotationY);
+ } else {
+ a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
+ a.setInterpolator(mFastFadeInterpolator);
+ }
+ anims.add(a);
+ }
+
+ int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+ mChildrenTransformsAnimator = new AnimatorSet();
+ mChildrenTransformsAnimator.playTogether(anims);
+
+ mChildrenTransformsAnimator.setDuration(duration);
+ mChildrenTransformsAnimator.start();
+ }
+
+ protected void reorderStarting() {
+ mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+ animatePagesToNeutral();
+ }
+
+ protected boolean zoomIn(final Runnable onCompleteRunnable) {
+ animatePagesToCarousel();
+ return super.zoomIn(onCompleteRunnable);
+ }
+
+ @Override
+ protected void onEndReordering() {
+ super.onEndReordering();
+ mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index e9c90a7..b1ff049 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -62,7 +62,7 @@
private float mBackgroundAlphaMultiplier = 1.0f;
private Drawable mBackgroundDrawable;
private Rect mBackgroundRect = new Rect();
- private static int mSmallWidgetHeight;
+ private int mSmallWidgetHeight;
// 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.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index 800ccc0..667b2d6 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -24,7 +24,10 @@
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.content.res.Resources;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.util.AttributeSet;
+import android.util.Slog;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -33,7 +36,6 @@
import android.widget.FrameLayout;
import com.android.internal.R;
-
import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
@@ -46,7 +48,7 @@
protected static float OVERSCROLL_MAX_ROTATION = 30;
private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
- private KeyguardViewStateManager mViewStateManager;
+ protected KeyguardViewStateManager mViewStateManager;
private LockPatternUtils mLockPatternUtils;
// Related to the fading in / out background outlines
@@ -58,15 +60,20 @@
protected int mScreenCenter;
private boolean mHasLayout = false;
private boolean mHasMeasure = false;
- private boolean mShowHintsOnLayout = false;
+ boolean showHintsAfterLayout = false;
private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
+ private static final String TAG = "KeyguardWidgetPager";
private int mPage = 0;
private Callbacks mCallbacks;
private boolean mCameraWidgetEnabled;
+ // Background threads to deal with persistence
+ private HandlerThread mBgPersistenceWorkerThread;
+ private Handler mBgPersistenceWorkerHandler;
+
public KeyguardWidgetPager(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -85,6 +92,9 @@
Resources r = getResources();
mCameraWidgetEnabled = r.getBoolean(R.bool.kg_enable_camera_default_widget);
+ mBgPersistenceWorkerThread = new HandlerThread("KeyguardWidgetPager Persistence");
+ mBgPersistenceWorkerThread.start();
+ mBgPersistenceWorkerHandler = new Handler(mBgPersistenceWorkerThread.getLooper());
}
public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
@@ -179,17 +189,28 @@
public void onRemoveView(View v) {
- int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
- mLockPatternUtils.removeAppWidget(appWidgetId);
+ final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+ mBgPersistenceWorkerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mLockPatternUtils.removeAppWidget(appWidgetId);
+ }
+ });
}
- public void onAddView(View v, int index) {
- int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
- getVisiblePages(mTempVisiblePagesRange);
- boundByReorderablePages(true, mTempVisiblePagesRange);
+ public void onAddView(View v, final int index) {
+ final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+ final int[] pagesRange = new int[mTempVisiblePagesRange.length];
+ getVisiblePages(pagesRange);
+ boundByReorderablePages(true, pagesRange);
// Subtract from the index to take into account pages before the reorderable
// pages (e.g. the "add widget" page)
- mLockPatternUtils.addAppWidget(appWidgetId, index - mTempVisiblePagesRange[0]);
+ mBgPersistenceWorkerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
+ }
+ });
}
/*
@@ -226,25 +247,40 @@
}
}
- // We enforce that all children are KeyguardWidgetFrames
+ /**
+ * Use addWidget() instead.
+ * @deprecated
+ */
@Override
public void addView(View child, int index) {
enforceKeyguardWidgetFrame(child);
super.addView(child, index);
}
+ /**
+ * Use addWidget() instead.
+ * @deprecated
+ */
@Override
public void addView(View child, int width, int height) {
enforceKeyguardWidgetFrame(child);
super.addView(child, width, height);
}
+ /**
+ * Use addWidget() instead.
+ * @deprecated
+ */
@Override
public void addView(View child, LayoutParams params) {
enforceKeyguardWidgetFrame(child);
super.addView(child, params);
}
+ /**
+ * Use addWidget() instead.
+ * @deprecated
+ */
@Override
public void addView(View child, int index, LayoutParams params) {
enforceKeyguardWidgetFrame(child);
@@ -272,7 +308,9 @@
if (mViewStateManager != null) {
mViewStateManager.onPageBeginMoving();
}
- showOutlinesAndSidePages();
+ if (!isReordering(false)) {
+ showOutlinesAndSidePages();
+ }
userActivity();
}
@@ -281,17 +319,22 @@
if (mViewStateManager != null) {
mViewStateManager.onPageEndMoving();
}
- hideOutlinesAndSidePages();
+
+ // In the reordering case, the pages will be faded appropriately on completion
+ // of the zoom in animation.
+ if (!isReordering(false)) {
+ hideOutlinesAndSidePages();
+ }
}
- private void enablePageLayers() {
+ protected void enablePageLayers() {
int children = getChildCount();
for (int i = 0; i < children; i++) {
getWidgetPageAt(i).enableHardwareLayersForContent();
}
}
- private void disablePageLayers() {
+ protected void disablePageLayers() {
int children = getChildCount();
for (int i = 0; i < children; i++) {
getWidgetPageAt(i).disableHardwareLayersForContent();
@@ -414,17 +457,21 @@
return true;
}
boolean isMusicWidgetVisible() {
- // TODO: Make proper test once we have music in the list
- return false;
+ return mViewStateManager.getTransportState() != KeyguardViewStateManager.TRANSPORT_GONE;
}
boolean isCameraWidgetVisible() {
return mCameraWidgetEnabled;
}
+ protected void reorderStarting() {
+ showOutlinesAndSidePages();
+ }
+
@Override
protected void onStartReordering() {
super.onStartReordering();
- showOutlinesAndSidePages();
+ enablePageLayers();
+ reorderStarting();
}
@Override
@@ -434,7 +481,6 @@
}
void showOutlinesAndSidePages() {
- enablePageLayers();
animateOutlinesAndSidePages(true);
}
@@ -447,7 +493,7 @@
showOutlinesAndSidePages();
} else {
// The layout hints depend on layout being run once
- mShowHintsOnLayout = true;
+ showHintsAfterLayout = true;
}
}
@@ -458,16 +504,17 @@
mHasLayout = false;
}
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (mShowHintsOnLayout) {
+ if (showHintsAfterLayout) {
post(new Runnable() {
@Override
public void run() {
showOutlinesAndSidePages();
}
});
- mShowHintsOnLayout = false;
+ showHintsAfterLayout = false;
}
mHasLayout = true;
}
@@ -504,17 +551,22 @@
}
void animateOutlinesAndSidePages(final boolean show) {
+ animateOutlinesAndSidePages(show, -1);
+ }
+
+ void animateOutlinesAndSidePages(final boolean show, int duration) {
if (mChildrenOutlineFadeAnimation != null) {
mChildrenOutlineFadeAnimation.cancel();
mChildrenOutlineFadeAnimation = null;
}
-
int count = getChildCount();
PropertyValuesHolder alpha;
ArrayList<Animator> anims = new ArrayList<Animator>();
- int duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
- CHILDREN_OUTLINE_FADE_OUT_DURATION;
+ if (duration == -1) {
+ duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
+ CHILDREN_OUTLINE_FADE_OUT_DURATION;
+ }
int curPage = getNextPage();
for (int i = 0; i < count; i++) {
@@ -541,6 +593,12 @@
mChildrenOutlineFadeAnimation.setDuration(duration);
mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ if (show) {
+ enablePageLayers();
+ }
+ }
+ @Override
public void onAnimationEnd(Animator animation) {
if (!show) {
disablePageLayers();
@@ -589,9 +647,37 @@
@Override
public boolean onLongClick(View v) {
// Disallow long pressing to reorder if the challenge is showing
- if (!mViewStateManager.isChallengeShowing() && startReordering()) {
+ boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
+ mViewStateManager.isChallengeOverlapping();
+ if (!isChallengeOverlapping && startReordering()) {
return true;
}
return false;
}
+
+ public void removeWidget(View view) {
+ if (view instanceof KeyguardWidgetFrame) {
+ removeView(view);
+ } else {
+ // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
+ // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
+ int pos = getWidgetPageIndex(view);
+ if (pos != -1) {
+ KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
+ frame.removeView(view);
+ removeView(frame);
+ } else {
+ Slog.w(TAG, "removeWidget() can't find:" + view);
+ }
+ }
+ }
+
+ public int getWidgetPageIndex(View view) {
+ if (view instanceof KeyguardWidgetFrame) {
+ return indexOfChild(view);
+ } else {
+ // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
+ return indexOfChild((KeyguardWidgetFrame)view.getParent());
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
index a207f5d..b38eb28 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
@@ -16,6 +16,10 @@
package com.android.internal.policy.impl.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
@@ -35,8 +39,9 @@
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
+ protected static final int ANIMATE_BOUNCE_DURATION = 750;
- private View mChallengeView;
+ private KeyguardSecurityContainer mChallengeView;
private View mUserSwitcherView;
private View mScrimView;
private OnBouncerStateChangedListener mBouncerListener;
@@ -87,7 +92,19 @@
if (mIsBouncing) return;
mIsBouncing = true;
if (mScrimView != null) {
- mScrimView.setVisibility(GONE);
+ if (mChallengeView != null) {
+ mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION);
+ }
+
+ Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
+ anim.setDuration(ANIMATE_BOUNCE_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mScrimView.setVisibility(VISIBLE);
+ }
+ });
+ anim.start();
}
if (mBouncerListener != null) {
mBouncerListener.onBouncerStateChanged(true);
@@ -99,7 +116,19 @@
if (!mIsBouncing) return;
mIsBouncing = false;
if (mScrimView != null) {
- mScrimView.setVisibility(GONE);
+ if (mChallengeView != null) {
+ mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION);
+ }
+
+ Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
+ anim.setDuration(ANIMATE_BOUNCE_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mScrimView.setVisibility(INVISIBLE);
+ }
+ });
+ anim.start();
}
if (mBouncerListener != null) {
mBouncerListener.onBouncerStateChanged(false);
@@ -131,7 +160,8 @@
mScrimView.setOnClickListener(null);
}
mScrimView = scrim;
- mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
+ mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
+ mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
mScrimView.setFocusable(true);
mScrimView.setOnClickListener(mScrimClickListener);
}
@@ -165,7 +195,11 @@
throw new IllegalStateException(
"There may only be one child of type challenge");
}
- mChallengeView = child;
+ if (!(child instanceof KeyguardSecurityContainer)) {
+ throw new IllegalArgumentException(
+ "Challenge must be a KeyguardSecurityContainer");
+ }
+ mChallengeView = (KeyguardSecurityContainer) child;
} else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
if (mUserSwitcherView != null) {
throw new IllegalStateException(
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
index 060cc03..ca36007 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
@@ -22,7 +22,9 @@
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;
@@ -72,6 +74,7 @@
setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0));
setOnClickListener(mListener);
+ setOnHoverListener(new LiftToActivateListener(context));
mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
@@ -113,4 +116,45 @@
| HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
}
+
+ /**
+ * Hover listener that implements lift-to-activate interaction for
+ * accessibility. May be added to multiple views.
+ */
+ static class LiftToActivateListener implements View.OnHoverListener {
+ /** Manager used to query accessibility enabled state. */
+ private final AccessibilityManager mAccessibilityManager;
+
+ public LiftToActivateListener(Context context) {
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ }
+
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ // When touch exploration is turned on, lifting a finger while
+ // inside the view bounds should perform a click action.
+ if (mAccessibilityManager.isEnabled()
+ && mAccessibilityManager.isTouchExplorationEnabled()) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ // Lift-to-type temporarily disables double-tap
+ // activation.
+ v.setClickable(false);
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+ if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
+ && (x < v.getWidth() - v.getPaddingRight())
+ && (y < v.getHeight() - v.getPaddingBottom())) {
+ v.performClick();
+ }
+ v.setClickable(true);
+ break;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 657a31f..c93b11a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -1995,7 +1995,7 @@
}
// "Zooms out" the PagedView to reveal more side pages
- boolean zoomOut() {
+ protected boolean zoomOut() {
if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
mZoomInOutAnim.cancel();
}
@@ -2072,15 +2072,15 @@
// If we haven't flung-to-delete the current child, then we just animate the drag view
// back into position
+ final Runnable onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ onEndReordering();
+ }
+ };
if (!mIsFlingingToDelete) {
mPostReorderingPreZoomInRunnable = new Runnable() {
public void run() {
- Runnable onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- onEndReordering();
- }
- };
zoomIn(onCompleteRunnable);
};
};
@@ -2091,11 +2091,13 @@
snapToPage(indexOfChild(mDragView), 0);
// Animate the drag view back to the front position
animateDragViewToOriginalPosition();
+ } else {
+ zoomIn(onCompleteRunnable);
}
}
// "Zooms in" the PagedView to highlight the current page
- boolean zoomIn(final Runnable onCompleteRunnable) {
+ protected boolean zoomIn(final Runnable onCompleteRunnable) {
if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
mZoomInOutAnim.cancel();
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
index ec6472f..7760279 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
@@ -24,4 +24,8 @@
public void setMessage(int resId, boolean important, Object... formatArgs);
public void setTimeout(int timeout_ms);
+
+ public void showBouncer(int animationDuration);
+
+ public void hideBouncer(int animationDuration);
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
index 35eccbb..2e735a0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -16,11 +16,15 @@
package com.android.internal.policy.impl.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -61,10 +65,12 @@
private Drawable mHandleDrawable;
private Drawable mFrameDrawable;
private Drawable mDragIconDrawable;
+ private boolean mEdgeCaptured;
// Initialized during measurement from child layoutparams
private View mChallengeView;
private View mScrimView;
+ private View mWidgetsView;
// Range: 0 (fully hidden) to 1 (fully visible)
private float mChallengeOffset = 1.f;
@@ -110,9 +116,14 @@
float mHandleAlpha;
float mFrameAlpha;
+ float mFrameAnimationTarget = Float.MIN_VALUE;
private ObjectAnimator mHandleAnimation;
private ObjectAnimator mFrameAnimation;
+ private final Rect mTempRect = new Rect();
+
+ private boolean mHasGlowpad;
+
static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
@Override
@@ -237,12 +248,12 @@
mMinVelocity = vc.getScaledMinimumFlingVelocity();
mMaxVelocity = vc.getScaledMaximumFlingVelocity();
- mDragHandleEdgeSlop = getResources().getDimensionPixelSize(
- R.dimen.kg_edge_swipe_region_size);
+ final Resources res = getResources();
+ mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- final float density = getResources().getDisplayMetrics().density;
+ final float density = res.getDisplayMetrics().density;
// top half of the lock icon, plus another 25% to be sure
mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
@@ -251,7 +262,7 @@
mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
// how much space to account for in the handle when closed
- mChallengeBottomBound = mDragHandleClosedBelow;
+ mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
setWillNotDraw(false);
}
@@ -293,21 +304,43 @@
mHandleAnimation.start();
}
- void animateFrame(boolean visible, boolean full) {
+ void animateFrame(final boolean visible, final boolean full) {
if (mFrameDrawable == null) return;
- if (mFrameAnimation != null) {
- mFrameAnimation.cancel();
- mFrameAnimation = null;
- }
final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f;
- if (targetAlpha == mFrameAlpha) {
+ if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) {
+ mFrameAnimation.cancel();
+ mFrameAnimationTarget = Float.MIN_VALUE;
+ }
+ if (targetAlpha == mFrameAlpha || targetAlpha == mFrameAnimationTarget) {
return;
}
+ mFrameAnimationTarget = targetAlpha;
mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha);
mFrameAnimation.setInterpolator(sHandleFadeInterpolator);
mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION);
+ mFrameAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mFrameAnimationTarget = Float.MIN_VALUE;
+
+ if (!visible && full && mChallengeView != null) {
+ // Mess with padding/margin to remove insets on the bouncer frame.
+ mChallengeView.setPadding(0, 0, 0, 0);
+ LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
+ lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
+ mChallengeView.setLayoutParams(lp);
+ }
+ mFrameAnimation = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mFrameAnimationTarget = Float.MIN_VALUE;
+ mFrameAnimation = null;
+ }
+ });
mFrameAnimation.start();
}
@@ -370,7 +403,9 @@
mScrollState = state;
animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
- animateFrame(false , false);
+ if (!mIsBouncing) {
+ animateFrame(false, false);
+ }
if (mScrollListener != null) {
mScrollListener.onScrollStateChanged(state);
}
@@ -380,6 +415,7 @@
void completeChallengeScroll() {
setChallengeShowing(mChallengeOffset != 0);
setScrollState(SCROLL_STATE_IDLE);
+ mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
}
void setScrimView(View scrim) {
@@ -461,7 +497,22 @@
if (mScrimView != null) {
mScrimView.setVisibility(VISIBLE);
}
+
+ // Mess with padding/margin to inset the bouncer frame.
+ // We have more space available to us otherwise.
+ if (mChallengeView != null) {
+ if (mFrameDrawable == null || !mFrameDrawable.getPadding(mTempRect)) {
+ mTempRect.set(0, 0, 0, 0);
+ }
+ mChallengeView.setPadding(mTempRect.left, mTempRect.top, mTempRect.right,
+ mTempRect.bottom);
+ final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
+ lp.leftMargin = lp.rightMargin = getChallengeMargin(false);
+ mChallengeView.setLayoutParams(lp);
+ }
+
animateFrame(true, true);
+
if (mBouncerListener != null) {
mBouncerListener.onBouncerStateChanged(true);
}
@@ -470,17 +521,26 @@
@Override
public void hideBouncer() {
if (!mIsBouncing) return;
- setChallengeShowing(false);
+ showChallenge(false);
mIsBouncing = false;
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
- animateFrame(false, false);
+ animateFrame(false, true);
if (mBouncerListener != null) {
mBouncerListener.onBouncerStateChanged(false);
}
}
+ private int getChallengeMargin(boolean expanded) {
+ return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
+ }
+
+ private float getChallengeAlpha() {
+ float x = mChallengeOffset - 1;
+ return x * x * x + 1.f;
+ }
+
@Override
public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
// We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
@@ -495,8 +555,6 @@
}
mVelocityTracker.addMovement(ev);
- //Log.v(TAG, "onIntercept: " + ev);
-
final int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -518,13 +576,15 @@
if (!mIsBouncing &&
(isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
- (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) &&
+ (isInChallengeView(x, y) &&
+ (mScrollState == SCROLL_STATE_SETTLING || !mChallengeShowing))) &&
mActivePointerId == INVALID_POINTER) {
mActivePointerId = ev.getPointerId(i);
mGestureStartX = x;
mGestureStartY = y;
mGestureStartChallengeBottom = getChallengeBottom();
mDragging = true;
+ mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
} else if (isInChallengeView(x, y)) {
mBlockDrag = true;
}
@@ -601,6 +661,7 @@
mActivePointerId = ev.getPointerId(i);
mGestureStartChallengeBottom = getChallengeBottom();
mDragging = true;
+ mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
break;
}
}
@@ -631,6 +692,52 @@
}
/**
+ * The lifecycle of touch events is subtle and it's very easy to do something
+ * that will cause bugs that will be nasty to track when overriding this method.
+ * Normally one should always override onInterceptTouchEvent instead.
+ *
+ * To put it another way, don't try this at home.
+ */
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ final int action = ev.getActionMasked();
+ boolean handled = false;
+ if (action == MotionEvent.ACTION_DOWN) {
+ // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
+ mEdgeCaptured = false;
+ }
+ if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
+ // Normally we would need to do a lot of extra stuff here.
+ // We can only get away with this because we haven't padded in
+ // the widget pager or otherwise transformed it during layout.
+ // We also don't support things like splitting MotionEvents.
+
+ // We set handled to captured even if dispatch is returning false here so that
+ // we don't send a different view a busted or incomplete event stream.
+ handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
+ }
+
+ if (!handled && !mEdgeCaptured) {
+ handled = super.dispatchTouchEvent(ev);
+ }
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mEdgeCaptured = false;
+ }
+
+ return handled;
+ }
+
+ private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
+ if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ return false;
+ }
+
+ final float x = ev.getX();
+ return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
+ }
+
+ /**
* We only want to add additional vertical space to the drag handle when the panel is fully
* closed.
*/
@@ -699,14 +806,24 @@
}
// We're going to play silly games with the frame's background drawable later.
mFrameDrawable = mChallengeView.getBackground();
+
+ if (!mHasLayout) {
+ // Set up the margin correctly based on our content for the first run.
+ mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
+ lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
+ }
} else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
setScrimView(child);
+ } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
+ mWidgetsView = child;
}
+
if (child.getVisibility() == GONE) continue;
}
- // We want to measure the challenge view first, for various reasons that I'd rather
- // not get into here.
+ // We want to measure the challenge view first, since the KeyguardWidgetPager
+ // needs to do things its measure pass that are dependent on the challenge view
+ // having been measured.
if (mChallengeView != null) {
measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0);
}
@@ -750,7 +867,7 @@
// we never want less than the handle size showing at the bottom.
final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
* (1 - mChallengeOffset));
- child.setAlpha(mChallengeOffset / 2 + 0.5f);
+ child.setAlpha(getChallengeAlpha());
child.layout(left, bottom - childHeight, left + childWidth, bottom);
} else {
// Non-challenge views lay out from the upper left, layered.
@@ -828,7 +945,7 @@
}
if (mDragIconDrawable != null) {
- final int closedTop = getLayoutBottom() - mChallengeBottomBound;
+ final int closedTop = getLayoutBottom() - mDragHandleClosedBelow;
final int iconWidth = mDragIconDrawable.getIntrinsicWidth();
final int iconHeight = mDragIconDrawable.getIntrinsicHeight();
final int iconLeft = (challengeLeft + challengeRight - iconWidth) / 2;
@@ -886,7 +1003,7 @@
mChallengeView.layout(mChallengeView.getLeft(),
bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
- mChallengeView.setAlpha(offset / 2 + 0.5f);
+ mChallengeView.setAlpha(getChallengeAlpha());
if (mScrollListener != null) {
mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
}
@@ -978,6 +1095,7 @@
public static final int CHILD_TYPE_NONE = 0;
public static final int CHILD_TYPE_CHALLENGE = 2;
public static final int CHILD_TYPE_SCRIM = 4;
+ public static final int CHILD_TYPE_WIDGETS = 5;
public LayoutParams() {
this(MATCH_PARENT, WRAP_CONTENT);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 4a54efe..0e171cd 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -889,7 +889,7 @@
final boolean isSystemNotification = ("android".equals(pkg));
userId = ActivityManager.handleIncomingUser(callingPid,
- callingUid, userId, true, true, "enqueueNotification", pkg);
+ callingUid, userId, true, false, "enqueueNotification", pkg);
final UserHandle user = new UserHandle(userId);
// Limit the number of notifications that any given package except the android
@@ -1287,7 +1287,7 @@
public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
checkCallerIsSystemOrSameApp(pkg);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, true, "cancelNotificationWithTag", pkg);
+ Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
// Don't allow client applications to cancel foreground service notis.
cancelNotification(pkg, tag, id, 0,
Binder.getCallingUid() == Process.SYSTEM_UID
@@ -1298,7 +1298,7 @@
checkCallerIsSystemOrSameApp(pkg);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, true, "cancelAllNotifications", pkg);
+ Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
// Calling from user space, don't allow the canceling of actively
// running foreground services.
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index a02fc8d..82dbf54 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -466,10 +466,13 @@
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
- } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
- onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL));
}
+ // TODO: Race condition causing problems when cleaning up on stopping a user.
+ // Comment this out for now.
+ // else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+ // onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ // UserHandle.USER_NULL));
+ // }
}
}, userFilter);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5722326..d2cd646 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4575,7 +4575,7 @@
int callingUid = Binder.getCallingUid();
int origUserId = userId;
userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
- type == ActivityManager.INTENT_SENDER_BROADCAST, true,
+ type == ActivityManager.INTENT_SENDER_BROADCAST, false,
"getIntentSender", null);
if (origUserId == UserHandle.USER_CURRENT) {
// We don't want to evaluate this until the pending intent is
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 637f2de..7958f9a 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2773,7 +2773,7 @@
// TODO: Remove once b/7094175 is fixed
|| ((String)win.mAttrs.getTitle()).contains("Keyguard")
) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
- + " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
+ + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
@@ -3003,6 +3003,10 @@
}
mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+ if (DEBUG_LAYOUT) {
+ Slog.v(TAG, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
+ }
}
if (configChanged) {
@@ -8379,7 +8383,8 @@
// windows, since that means "perform layout as normal,
// just don't display").
if (!gone || !win.mHaveFrame || win.mLayoutNeeded
- || win.isConfigChanged()
+ || ((win.mAttrs.type == TYPE_KEYGUARD || win.mAttrs.type == TYPE_WALLPAPER) &&
+ win.isConfigChanged())
|| win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
if (!win.mLayoutAttached) {
if (initial) {
@@ -9301,6 +9306,8 @@
Log.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
Surface.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
final WindowList defaultWindows = defaultDisplay.getWindowList();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index c195f45..0a9c3e5 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -282,7 +282,7 @@
mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Window " + this + " client=" + c.asBinder()
- + " token=" + token + " (" + mAttrs.token + ")");
+ + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
try {
c.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {