summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/17.txt34
-rw-r--r--api/current.txt34
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java14
-rw-r--r--core/java/android/text/format/DateFormat.java97
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/webkit/AccessibilityInjector.java163
-rw-r--r--core/java/android/webkit/WebViewClassic.java3
-rw-r--r--core/java/android/widget/DigitalClock.java31
-rw-r--r--core/java/android/widget/TextClock.java482
-rw-r--r--core/java/com/android/internal/policy/IFaceLockInterface.aidl1
-rw-r--r--core/java/com/android/internal/widget/FaceUnlockView.java69
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java5
-rw-r--r--core/res/AndroidManifest.xml13
-rw-r--r--core/res/res/layout-land/keyguard_host_view.xml8
-rw-r--r--core/res/res/layout-port/keyguard_host_view.xml14
-rw-r--r--core/res/res/layout-port/keyguard_widget_pager.xml2
-rw-r--r--core/res/res/layout/keyguard_face_unlock_view.xml7
-rw-r--r--core/res/res/layout/keyguard_password_view.xml104
-rw-r--r--core/res/res/layout/keyguard_pin_view.xml28
-rw-r--r--core/res/res/values-land/dimens.xml6
-rw-r--r--core/res/res/values-sw380dp/dimens.xml23
-rw-r--r--core/res/res/values-sw600dp/dimens.xml4
-rw-r--r--core/res/res/values-sw720dp/dimens.xml9
-rwxr-xr-xcore/res/res/values/attrs.xml20
-rwxr-xr-xcore/res/res/values/config.xml6
-rw-r--r--core/res/res/values/dimens.xml8
-rw-r--r--core/res/res/values/integers.xml4
-rw-r--r--core/res/res/values/public.xml3
-rwxr-xr-xcore/res/res/values/strings.xml35
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--core/tests/ConnectivityManagerTest/AndroidManifest.xml1
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java47
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java6
-rw-r--r--docs/html/distribute/googleplay/publish/preparing.jd2
-rw-r--r--docs/html/guide/google/play/expansion-files.jd6
-rw-r--r--docs/html/guide/topics/ui/notifiers/notifications.jd128
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java5
-rw-r--r--libs/hwui/OpenGLRenderer.cpp2
-rw-r--r--location/java/android/location/Geofence.java4
-rw-r--r--location/java/android/location/Location.java8
-rw-r--r--location/java/android/location/LocationManager.java8
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java17
-rw-r--r--packages/FusedLocation/Android.mk1
-rw-r--r--packages/FusedLocation/src/com/android/location/fused/FusionEngine.java22
-rw-r--r--packages/SystemUI/res/layout-land/status_bar_recent_panel.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_recent_panel.xml3
-rw-r--r--packages/SystemUI/res/layout/system_bar_recent_panel.xml3
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java29
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java65
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java44
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java7
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java183
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java47
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java48
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java8
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java11
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java30
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java165
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java138
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java44
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java44
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/PagedView.java18
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java4
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java158
-rwxr-xr-xservices/java/com/android/server/BluetoothManagerService.java62
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java6
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java9
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/java/com/android/server/wm/AppWindowAnimator.java21
-rw-r--r--services/java/com/android/server/wm/WindowAnimator.java173
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java57
-rw-r--r--services/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java9
86 files changed, 2414 insertions, 537 deletions
diff --git a/api/17.txt b/api/17.txt
index e26d8f0..fde6302 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -491,6 +491,8 @@ package android {
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int format = 16843013; // 0x1010105
+ field public static final int format12Hour = 16843722; // 0x10103ca
+ field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fragment = 16843491; // 0x10102e3
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
@@ -1074,6 +1076,7 @@ package android {
field public static final int thumbTextPadding = 16843634; // 0x1010372
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
+ field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
@@ -22300,14 +22303,14 @@ package android.text.format {
public class DateFormat {
ctor public DateFormat();
- method public static final java.lang.CharSequence format(java.lang.CharSequence, long);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
- method public static final java.text.DateFormat getDateFormat(android.content.Context);
- method public static final char[] getDateFormatOrder(android.content.Context);
- method public static final java.text.DateFormat getLongDateFormat(android.content.Context);
- method public static final java.text.DateFormat getMediumDateFormat(android.content.Context);
- method public static final java.text.DateFormat getTimeFormat(android.content.Context);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, long);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
+ method public static java.text.DateFormat getDateFormat(android.content.Context);
+ method public static char[] getDateFormatOrder(android.content.Context);
+ method public static java.text.DateFormat getLongDateFormat(android.content.Context);
+ method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
+ method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
field public static final char AM_PM = 97; // 0x0061 'a'
field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
@@ -29518,6 +29521,21 @@ package android.widget {
field public int span;
}
+ public class TextClock extends android.widget.TextView {
+ ctor public TextClock(android.content.Context);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet, int);
+ method public java.lang.CharSequence getFormat12Hour();
+ method public java.lang.CharSequence getFormat24Hour();
+ method public java.lang.String getTimeZone();
+ method public boolean is24HourModeEnabled();
+ method public void setFormat12Hour(java.lang.CharSequence);
+ method public void setFormat24Hour(java.lang.CharSequence);
+ method public void setTimeZone(java.lang.String);
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+ }
+
public class TextSwitcher extends android.widget.ViewSwitcher {
ctor public TextSwitcher(android.content.Context);
ctor public TextSwitcher(android.content.Context, android.util.AttributeSet);
diff --git a/api/current.txt b/api/current.txt
index e26d8f0..fde6302 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -491,6 +491,8 @@ package android {
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int format = 16843013; // 0x1010105
+ field public static final int format12Hour = 16843722; // 0x10103ca
+ field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fragment = 16843491; // 0x10102e3
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
@@ -1074,6 +1076,7 @@ package android {
field public static final int thumbTextPadding = 16843634; // 0x1010372
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
+ field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
@@ -22300,14 +22303,14 @@ package android.text.format {
public class DateFormat {
ctor public DateFormat();
- method public static final java.lang.CharSequence format(java.lang.CharSequence, long);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
- method public static final java.text.DateFormat getDateFormat(android.content.Context);
- method public static final char[] getDateFormatOrder(android.content.Context);
- method public static final java.text.DateFormat getLongDateFormat(android.content.Context);
- method public static final java.text.DateFormat getMediumDateFormat(android.content.Context);
- method public static final java.text.DateFormat getTimeFormat(android.content.Context);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, long);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
+ method public static java.text.DateFormat getDateFormat(android.content.Context);
+ method public static char[] getDateFormatOrder(android.content.Context);
+ method public static java.text.DateFormat getLongDateFormat(android.content.Context);
+ method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
+ method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
field public static final char AM_PM = 97; // 0x0061 'a'
field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
@@ -29518,6 +29521,21 @@ package android.widget {
field public int span;
}
+ public class TextClock extends android.widget.TextView {
+ ctor public TextClock(android.content.Context);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet, int);
+ method public java.lang.CharSequence getFormat12Hour();
+ method public java.lang.CharSequence getFormat24Hour();
+ method public java.lang.String getTimeZone();
+ method public boolean is24HourModeEnabled();
+ method public void setFormat12Hour(java.lang.CharSequence);
+ method public void setFormat24Hour(java.lang.CharSequence);
+ method public void setTimeZone(java.lang.String);
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+ }
+
public class TextSwitcher extends android.widget.ViewSwitcher {
ctor public TextSwitcher(android.content.Context);
ctor public TextSwitcher(android.content.Context, android.util.AttributeSet);
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 class AppWidgetManager {
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 class AppWidgetManager {
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/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index c36273e..3c984b5 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -249,12 +249,13 @@ public class DateFormat {
synchronized (sLocaleLock) {
sIs24HourLocale = locale;
- sIs24Hour = !value.equals("12");
+ sIs24Hour = value.equals("24");
}
+
+ return sIs24Hour;
}
- boolean b24 = !(value == null || value.equals("12"));
- return b24;
+ return value.equals("24");
}
/**
@@ -263,7 +264,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that properly formats the time.
*/
- public static final java.text.DateFormat getTimeFormat(Context context) {
+ public static java.text.DateFormat getTimeFormat(Context context) {
boolean b24 = is24HourFormat(context);
int res;
@@ -283,7 +284,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that properly formats the date.
*/
- public static final java.text.DateFormat getDateFormat(Context context) {
+ public static java.text.DateFormat getDateFormat(Context context) {
String value = Settings.System.getString(context.getContentResolver(),
Settings.System.DATE_FORMAT);
@@ -353,7 +354,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
- public static final java.text.DateFormat getLongDateFormat(Context context) {
+ public static java.text.DateFormat getLongDateFormat(Context context) {
return java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG);
}
@@ -363,7 +364,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
- public static final java.text.DateFormat getMediumDateFormat(Context context) {
+ public static java.text.DateFormat getMediumDateFormat(Context context) {
return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM);
}
@@ -376,7 +377,7 @@ public class DateFormat {
* not just the day, month, and year, and not necessarily in the same
* order returned here.
*/
- public static final char[] getDateFormatOrder(Context context) {
+ public static char[] getDateFormatOrder(Context context) {
char[] order = new char[] {DATE, MONTH, YEAR};
String value = getDateFormatString(context);
int index = 0;
@@ -420,7 +421,7 @@ public class DateFormat {
* @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, long inTimeInMillis) {
+ public static CharSequence format(CharSequence inFormat, long inTimeInMillis) {
return format(inFormat, new Date(inTimeInMillis));
}
@@ -431,7 +432,7 @@ public class DateFormat {
* @param inDate the date to format
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, Date inDate) {
+ public static CharSequence format(CharSequence inFormat, Date inDate) {
Calendar c = new GregorianCalendar();
c.setTime(inDate);
@@ -440,13 +441,75 @@ public class DateFormat {
}
/**
+ * Indicates whether the specified format string contains seconds.
+ *
+ * Always returns false if the input format is null.
+ *
+ * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
+ *
+ * @return true if the format string contains {@link #SECONDS}, false otherwise
+ *
+ * @hide
+ */
+ public static boolean hasSeconds(CharSequence inFormat) {
+ if (inFormat == null) return false;
+
+ final int length = inFormat.length();
+
+ int c;
+ int count;
+
+ for (int i = 0; i < length; i += count) {
+ count = 1;
+ c = inFormat.charAt(i);
+
+ if (c == QUOTE) {
+ count = skipQuotedText(inFormat, i, length);
+ } else if (c == SECONDS) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static int skipQuotedText(CharSequence s, int i, int len) {
+ if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
+ return 2;
+ }
+
+ int count = 1;
+ // skip leading quote
+ i++;
+
+ while (i < len) {
+ char c = s.charAt(i);
+
+ if (c == QUOTE) {
+ count++;
+ // QUOTEQUOTE -> QUOTE
+ if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
+ i++;
+ } else {
+ break;
+ }
+ } else {
+ i++;
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
* Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
* containing the requested date.
* @param inFormat the format string, as described in {@link android.text.format.DateFormat}
* @param inDate the date to format
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, Calendar inDate) {
+ public static CharSequence format(CharSequence inFormat, Calendar inDate) {
SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
int c;
int count;
@@ -545,7 +608,7 @@ public class DateFormat {
return s.toString();
}
- private static final String getMonthString(Calendar inDate, int count, int kind) {
+ private static String getMonthString(Calendar inDate, int count, int kind) {
boolean standalone = (kind == STANDALONE_MONTH);
int month = inDate.get(Calendar.MONTH);
@@ -563,7 +626,7 @@ public class DateFormat {
}
}
- private static final String getTimeZoneString(Calendar inDate, int count) {
+ private static String getTimeZoneString(Calendar inDate, int count) {
TimeZone tz = inDate.getTimeZone();
if (count < 2) { // FIXME: shouldn't this be <= 2 ?
@@ -576,7 +639,7 @@ public class DateFormat {
}
}
- private static final String formatZoneOffset(int offset, int count) {
+ private static String formatZoneOffset(int offset, int count) {
offset /= 1000; // milliseconds to seconds
StringBuilder tb = new StringBuilder();
@@ -595,13 +658,13 @@ public class DateFormat {
return tb.toString();
}
- private static final String getYearString(Calendar inDate, int count) {
+ private static String getYearString(Calendar inDate, int count) {
int year = inDate.get(Calendar.YEAR);
return (count <= 2) ? zeroPad(year % 100, 2)
: String.format(Locale.getDefault(), "%d", year);
}
- private static final int appendQuotedText(SpannableStringBuilder s, int i, int len) {
+ private static int appendQuotedText(SpannableStringBuilder s, int i, int len) {
if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
s.delete(i, i + 1);
return 1;
@@ -638,7 +701,7 @@ public class DateFormat {
return count;
}
- private static final String zeroPad(int inValue, int inMinDigits) {
+ private static String zeroPad(int inValue, int inMinDigits) {
return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9d0d4f0..d5e1ed3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17697,7 +17697,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mScalingRequired;
/**
- * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
+ * If set, ViewRootImpl doesn't use its lame animation for when the window resizes.
*/
boolean mTurnOffWindowResizeAnim;
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index 95a0416..008a615 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -18,6 +18,7 @@ package android.webkit;
import android.content.Context;
import android.os.Bundle;
+import android.os.Handler;
import android.os.SystemClock;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
@@ -159,7 +160,7 @@ class AccessibilityInjector {
* <p>
* This should only be called before a page loads.
*/
- private void addAccessibilityApisIfNecessary() {
+ public void addAccessibilityApisIfNecessary() {
if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) {
return;
}
@@ -333,8 +334,9 @@ class AccessibilityInjector {
*/
public void onPageStarted(String url) {
mAccessibilityScriptInjected = false;
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "[" + mWebView.hashCode() + "] Started loading new page");
+ }
addAccessibilityApisIfNecessary();
}
@@ -348,30 +350,57 @@ class AccessibilityInjector {
*/
public void onPageFinished(String url) {
if (!isAccessibilityEnabled()) {
- mAccessibilityScriptInjected = false;
toggleFallbackAccessibilityInjector(false);
return;
}
- if (!shouldInjectJavaScript(url)) {
- mAccessibilityScriptInjected = false;
- toggleFallbackAccessibilityInjector(true);
- if (DEBUG)
- Log.d(TAG, "[" + mWebView.hashCode() + "] Using fallback accessibility support");
- return;
+ toggleFallbackAccessibilityInjector(true);
+
+ if (shouldInjectJavaScript(url)) {
+ // If we're supposed to use the JS screen reader, request a
+ // callback to confirm that CallbackHandler is working.
+ if (DEBUG) {
+ Log.d(TAG, "[" + mWebView.hashCode() + "] Request callback ");
+ }
+
+ mCallback.requestCallback(mWebView, mInjectScriptRunnable);
+ }
+ }
+
+ /**
+ * Runnable used to inject the JavaScript-based screen reader if the
+ * {@link CallbackHandler} API was successfully exposed to JavaScript.
+ */
+ private Runnable mInjectScriptRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) {
+ Log.d(TAG, "[" + mWebView.hashCode() + "] Received callback");
+ }
+
+ injectJavaScript();
}
+ };
+ /**
+ * Called by {@link #mInjectScriptRunnable} to inject the JavaScript-based
+ * screen reader after confirming that the {@link CallbackHandler} API is
+ * functional.
+ */
+ private void injectJavaScript() {
toggleFallbackAccessibilityInjector(false);
if (!mAccessibilityScriptInjected) {
mAccessibilityScriptInjected = true;
final String injectionUrl = getScreenReaderInjectionUrl();
mWebView.loadUrl(injectionUrl);
- if (DEBUG)
+ if (DEBUG) {
Log.d(TAG, "[" + mWebView.hashCode() + "] Loading screen reader into WebView");
+ }
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "[" + mWebView.hashCode() + "] Attempted to inject screen reader twice");
+ }
}
}
@@ -447,12 +476,10 @@ class AccessibilityInjector {
* been done.
*/
private void addTtsApis() {
- if (mTextToSpeech != null) {
- return;
+ if (mTextToSpeech == null) {
+ mTextToSpeech = new TextToSpeechWrapper(mContext);
}
- if (DEBUG)
- Log.d(TAG, "[" + mWebView.hashCode() + "] Adding TTS APIs into WebView");
- mTextToSpeech = new TextToSpeechWrapper(mContext);
+
mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE);
}
@@ -461,34 +488,29 @@ class AccessibilityInjector {
* already been done.
*/
private void removeTtsApis() {
- if (mTextToSpeech == null) {
- return;
+ if (mTextToSpeech != null) {
+ mTextToSpeech.stop();
+ mTextToSpeech.shutdown();
+ mTextToSpeech = null;
}
- if (DEBUG)
- Log.d(TAG, "[" + mWebView.hashCode() + "] Removing TTS APIs from WebView");
mWebView.removeJavascriptInterface(ALIAS_TTS_JS_INTERFACE);
- mTextToSpeech.stop();
- mTextToSpeech.shutdown();
- mTextToSpeech = null;
}
private void addCallbackApis() {
- if (mCallback != null) {
- return;
+ if (mCallback == null) {
+ mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
}
- mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE);
}
private void removeCallbackApis() {
- if (mCallback == null) {
- return;
+ if (mCallback != null) {
+ mCallback = null;
}
mWebView.removeJavascriptInterface(ALIAS_TRAVERSAL_JS_INTERFACE);
- mCallback = null;
}
/**
@@ -638,9 +660,10 @@ class AccessibilityInjector {
private volatile boolean mShutdown;
public TextToSpeechWrapper(Context context) {
- if (DEBUG)
+ if (DEBUG) {
Log.d(WRAP_TAG, "[" + hashCode() + "] Initializing text-to-speech on thread "
+ Thread.currentThread().getId() + "...");
+ }
final String pkgName = context.getPackageName();
@@ -672,12 +695,14 @@ class AccessibilityInjector {
public int speak(String text, int queueMode, HashMap<String, String> params) {
synchronized (mTextToSpeech) {
if (!mReady) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(WRAP_TAG, "[" + hashCode() + "] Attempted to speak before TTS init");
+ }
return TextToSpeech.ERROR;
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.i(WRAP_TAG, "[" + hashCode() + "] Speak called from JS binder");
+ }
}
return mTextToSpeech.speak(text, queueMode, params);
@@ -689,12 +714,14 @@ class AccessibilityInjector {
public int stop() {
synchronized (mTextToSpeech) {
if (!mReady) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(WRAP_TAG, "[" + hashCode() + "] Attempted to stop before initialize");
+ }
return TextToSpeech.ERROR;
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.i(WRAP_TAG, "[" + hashCode() + "] Stop called from JS binder");
+ }
}
return mTextToSpeech.stop();
@@ -705,12 +732,14 @@ class AccessibilityInjector {
protected void shutdown() {
synchronized (mTextToSpeech) {
if (!mReady) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(WRAP_TAG, "[" + hashCode() + "] Called shutdown before initialize");
+ }
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.i(WRAP_TAG, "[" + hashCode() + "] Shutting down text-to-speech from "
+ "thread " + Thread.currentThread().getId() + "...");
+ }
}
mShutdown = true;
mReady = false;
@@ -723,14 +752,16 @@ class AccessibilityInjector {
public void onInit(int status) {
synchronized (mTextToSpeech) {
if (!mShutdown && (status == TextToSpeech.SUCCESS)) {
- if (DEBUG)
+ if (DEBUG) {
Log.d(WRAP_TAG, "[" + TextToSpeechWrapper.this.hashCode()
+ "] Initialized successfully");
+ }
mReady = true;
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.w(WRAP_TAG, "[" + TextToSpeechWrapper.this.hashCode()
+ "] Failed to initialize");
+ }
mReady = false;
}
}
@@ -745,9 +776,10 @@ class AccessibilityInjector {
@Override
public void onError(String utteranceId) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(WRAP_TAG, "[" + TextToSpeechWrapper.this.hashCode()
+ "] Failed to speak utterance");
+ }
}
@Override
@@ -770,12 +802,16 @@ class AccessibilityInjector {
private final AtomicInteger mResultIdCounter = new AtomicInteger();
private final Object mResultLock = new Object();
private final String mInterfaceName;
+ private final Handler mMainHandler;
+
+ private Runnable mCallbackRunnable;
private boolean mResult = false;
private int mResultId = -1;
private CallbackHandler(String interfaceName) {
mInterfaceName = interfaceName;
+ mMainHandler = new Handler();
}
/**
@@ -826,25 +862,29 @@ class AccessibilityInjector {
private boolean waitForResultTimedLocked(int resultId) {
final long startTimeMillis = SystemClock.uptimeMillis();
- if (DEBUG)
+ if (DEBUG) {
Log.d(TAG, "Waiting for CVOX result with ID " + resultId + "...");
+ }
while (true) {
// Fail if we received a callback from the future.
if (mResultId > resultId) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Aborted CVOX result");
+ }
return false;
}
final long elapsedTimeMillis = (SystemClock.uptimeMillis() - startTimeMillis);
// Succeed if we received the callback we were expecting.
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Check " + mResultId + " versus expected " + resultId);
+ }
if (mResultId == resultId) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Received CVOX result after " + elapsedTimeMillis + " ms");
+ }
return true;
}
@@ -852,18 +892,21 @@ class AccessibilityInjector {
// Fail if we've already exceeded the timeout.
if (waitTimeMillis <= 0) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Timed out while waiting for CVOX result");
+ }
return false;
}
try {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Start waiting...");
+ }
mResultLock.wait(waitTimeMillis);
} catch (InterruptedException ie) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Interrupted while waiting for CVOX result");
+ }
}
}
}
@@ -878,8 +921,9 @@ class AccessibilityInjector {
@JavascriptInterface
@SuppressWarnings("unused")
public void onResult(String id, String result) {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Saw CVOX result of '" + result + "' for ID " + id);
+ }
final int resultId;
try {
@@ -893,11 +937,34 @@ class AccessibilityInjector {
mResult = Boolean.parseBoolean(result);
mResultId = resultId;
} else {
- if (DEBUG)
+ if (DEBUG) {
Log.w(TAG, "Result with ID " + resultId + " was stale vesus " + mResultId);
+ }
}
mResultLock.notifyAll();
}
}
+
+ /**
+ * Requests a callback to ensure that the JavaScript interface for this
+ * object has been added successfully.
+ *
+ * @param webView The web view to request a callback from.
+ * @param callbackRunnable Runnable to execute if a callback is received.
+ */
+ public void requestCallback(WebView webView, Runnable callbackRunnable) {
+ mCallbackRunnable = callbackRunnable;
+
+ webView.loadUrl("javascript:(function() { " + mInterfaceName + ".callback(); })();");
+ }
+
+ @JavascriptInterface
+ @SuppressWarnings("unused")
+ public void callback() {
+ if (mCallbackRunnable != null) {
+ mMainHandler.post(mCallbackRunnable);
+ mCallbackRunnable = null;
+ }
+ }
}
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 0f8966e..ae56e6b 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -2500,6 +2500,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// Remove all pending messages because we are restoring previous
// state.
mWebViewCore.removeMessages();
+ if (isAccessibilityInjectionEnabled()) {
+ getAccessibilityInjector().addAccessibilityApisIfNecessary();
+ }
// Send a restore state message.
mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
}
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 3e9107f..c6b6dd6 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.SystemClock;
@@ -32,14 +31,12 @@ import java.util.Calendar;
/**
* Like AnalogClock, but digital. Shows seconds.
*
- * FIXME: implement separate views for hours/minutes/seconds, so
- * proportional fonts don't shake rendering
- *
- * @deprecated It is recommended you use a {@link TextView} and {@link DateFormat}
- * to implement the same behavior.
+ * @deprecated It is recommended you use {@link TextClock} instead.
*/
@Deprecated
public class DigitalClock extends TextView {
+ // FIXME: implement separate views for hours/minutes/seconds, so
+ // proportional fonts don't shake rendering
Calendar mCalendar;
private final static String m12 = "h:mm:ss aa";
@@ -86,16 +83,16 @@ public class DigitalClock extends TextView {
* requests a tick on the next hard-second boundary
*/
mTicker = new Runnable() {
- public void run() {
- if (mTickerStopped) return;
- mCalendar.setTimeInMillis(System.currentTimeMillis());
- setText(DateFormat.format(mFormat, mCalendar));
- invalidate();
- long now = SystemClock.uptimeMillis();
- long next = now + (1000 - now % 1000);
- mHandler.postAtTime(mTicker, next);
- }
- };
+ public void run() {
+ if (mTickerStopped) return;
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
+ setText(DateFormat.format(mFormat, mCalendar));
+ invalidate();
+ long now = SystemClock.uptimeMillis();
+ long next = now + (1000 - now % 1000);
+ mHandler.postAtTime(mTicker, next);
+ }
+ };
mTicker.run();
}
@@ -134,12 +131,14 @@ public class DigitalClock extends TextView {
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
+ //noinspection deprecation
event.setClassName(DigitalClock.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+ //noinspection deprecation
info.setClassName(DigitalClock.class.getName());
}
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
new file mode 100644
index 0000000..4c46658
--- /dev/null
+++ b/core/java/android/widget/TextClock.java
@@ -0,0 +1,482 @@
+/*
+ * 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 android.widget;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import static android.view.ViewDebug.ExportedProperty;
+import static android.widget.RemoteViews.*;
+
+/**
+ * <p><code>TextClock</code> can display the current date and/or time as
+ * a formatted string.</p>
+ *
+ * <p>This view honors the 24-hour format system setting. As such, it is
+ * possible and recommended to provide two different formatting patterns:
+ * one to display the date/time in 24-hour mode and one to display the
+ * date/time in 12-hour mode.</p>
+ *
+ * <p>It is possible to determine whether the system is currently in
+ * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
+ *
+ * <p>The rules used by this widget to decide how to format the date and
+ * time are the following:</p>
+ * <ul>
+ * <li>In 24-hour mode:
+ * <ul>
+ * <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
+ * <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
+ * <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li>
+ * </ul>
+ * </li>
+ * <li>In 12-hour mode:
+ * <ul>
+ * <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
+ * <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
+ * <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <p>The {@link CharSequence} instances used as formatting patterns when calling either
+ * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
+ * contain styling information. To do so, use a {@link android.text.Spanned} object.</p>
+ *
+ * @attr ref android.R.styleable#TextClock_format12Hour
+ * @attr ref android.R.styleable#TextClock_format24Hour
+ * @attr ref android.R.styleable#TextClock_timeZone
+ */
+@RemoteView
+public class TextClock extends TextView {
+ /**
+ * The default formatting pattern in 12-hour mode. This pattenr is used
+ * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
+ * or if no pattern was specified when creating an instance of this class.
+ *
+ * This default pattern shows only the time, hours and minutes, and an am/pm
+ * indicator.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #getFormat12Hour()
+ */
+ public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa";
+
+ /**
+ * The default formatting pattern in 24-hour mode. This pattenr is used
+ * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
+ * or if no pattern was specified when creating an instance of this class.
+ *
+ * This default pattern shows only the time, hours and minutes.
+ *
+ * @see #setFormat24Hour(CharSequence)
+ * @see #getFormat24Hour()
+ */
+ public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm";
+
+ private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR;
+ private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR;
+
+ @ExportedProperty
+ private CharSequence mFormat;
+ @ExportedProperty
+ private boolean mHasSeconds;
+
+ private boolean mAttached;
+
+ private Calendar mTime;
+ private String mTimeZone;
+
+ private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ chooseFormat();
+ onTimeChanged();
+ }
+ };
+
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mTimeZone == null) {
+ if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+ final String timeZone = intent.getStringExtra("time-zone");
+ createTime(timeZone);
+ }
+ onTimeChanged();
+ }
+ }
+ };
+
+ private final Runnable mTicker = new Runnable() {
+ public void run() {
+ onTimeChanged();
+
+ long now = SystemClock.uptimeMillis();
+ long next = now + (1000 - now % 1000);
+
+ getHandler().postAtTime(mTicker, next);
+ }
+ };
+
+ /**
+ * Creates a new clock using the default patterns
+ * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
+ * respectively for the 24-hour and 12-hour modes.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public TextClock(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Creates a new clock inflated from XML. This object's properties are
+ * intialized from the attributes specified in XML.
+ *
+ * This constructor uses a default style of 0, so the only attribute values
+ * applied are those in the Context's Theme and the given AttributeSet.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public TextClock(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * Creates a new clock inflated from XML. This object's properties are
+ * intialized from the attributes specified in XML.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view
+ * @param defStyle The default style to apply to this view. If 0, no style
+ * will be applied (beyond what is included in the theme). This may
+ * either be an attribute resource, whose value will be retrieved
+ * from the current theme, or an explicit style resource
+ */
+ public TextClock(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0);
+ try {
+ CharSequence format;
+
+ format = a.getText(R.styleable.TextClock_format12Hour);
+ mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format;
+
+ format = a.getText(R.styleable.TextClock_format24Hour);
+ mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format;
+
+ mTimeZone = a.getString(R.styleable.TextClock_timeZone);
+ } finally {
+ a.recycle();
+ }
+
+ init();
+ }
+
+ private void init() {
+ createTime(mTimeZone);
+ // Wait until onAttachedToWindow() to handle the ticker
+ chooseFormat(false);
+ }
+
+ private void createTime(String timeZone) {
+ if (timeZone != null) {
+ mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
+ } else {
+ mTime = Calendar.getInstance();
+ }
+ }
+
+ /**
+ * Returns the formatting pattern used to display the date and/or time
+ * in 12-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * @return A {@link CharSequence} or null.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #is24HourModeEnabled()
+ */
+ @ExportedProperty
+ public CharSequence getFormat12Hour() {
+ return mFormat12;
+ }
+
+ /**
+ * Specifies the formatting pattern used to display the date and/or time
+ * in 12-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * If this pattern is set to null, {@link #getFormat24Hour()} will be used
+ * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
+ * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
+ * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+ *
+ * @param format A date/time formatting pattern as described in {@link DateFormat}
+ *
+ * @see #getFormat12Hour()
+ * @see #is24HourModeEnabled()
+ * @see #DEFAULT_FORMAT_12_HOUR
+ * @see DateFormat
+ *
+ * @attr ref android.R.styleable#TextClock_format12Hour
+ */
+ public void setFormat12Hour(CharSequence format) {
+ mFormat12 = format;
+
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ /**
+ * Returns the formatting pattern used to display the date and/or time
+ * in 24-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * @return A {@link CharSequence} or null.
+ *
+ * @see #setFormat24Hour(CharSequence)
+ * @see #is24HourModeEnabled()
+ */
+ @ExportedProperty
+ public CharSequence getFormat24Hour() {
+ return mFormat24;
+ }
+
+ /**
+ * Specifies the formatting pattern used to display the date and/or time
+ * in 24-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * If this pattern is set to null, {@link #getFormat12Hour()} will be used
+ * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns
+ * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
+ * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+ *
+ * @param format A date/time formatting pattern as described in {@link DateFormat}
+ *
+ * @see #getFormat24Hour()
+ * @see #is24HourModeEnabled()
+ * @see #DEFAULT_FORMAT_24_HOUR
+ * @see DateFormat
+ *
+ * @attr ref android.R.styleable#TextClock_format24Hour
+ */
+ public void setFormat24Hour(CharSequence format) {
+ mFormat24 = format;
+
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ /**
+ * Indicates whether the system is currently using the 24-hour mode.
+ *
+ * When the system is in 24-hour mode, this view will use the pattern
+ * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
+ * returned by {@link #getFormat12Hour()} is used instead.
+ *
+ * If either one of the formats is null, the other format is used. If
+ * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
+ * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
+ *
+ * @return true if time should be displayed in 24-hour format, false if it
+ * should be displayed in 12-hour format.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #getFormat12Hour()
+ * @see #setFormat24Hour(CharSequence)
+ * @see #getFormat24Hour()
+ */
+ public boolean is24HourModeEnabled() {
+ return DateFormat.is24HourFormat(getContext());
+ }
+
+ /**
+ * Indicates which time zone is currently used by this view.
+ *
+ * @return The ID of the current time zone or null if the default time zone,
+ * as set by the user, must be used
+ *
+ * @see TimeZone
+ * @see java.util.TimeZone#getAvailableIDs()
+ * @see #setTimeZone(String)
+ */
+ public String getTimeZone() {
+ return mTimeZone;
+ }
+
+ /**
+ * Sets the specified time zone to use in this clock. When the time zone
+ * is set through this method, system time zone changes (when the user
+ * sets the time zone in settings for instance) will be ignored.
+ *
+ * @param timeZone The desired time zone's ID as specified in {@link TimeZone}
+ * or null to user the time zone specified by the user
+ * (system time zone)
+ *
+ * @see #getTimeZone()
+ * @see java.util.TimeZone#getAvailableIDs()
+ * @see TimeZone#getTimeZone(String)
+ *
+ * @attr ref android.R.styleable#TextClock_timeZone
+ */
+ public void setTimeZone(String timeZone) {
+ mTimeZone = timeZone;
+
+ createTime(timeZone);
+ onTimeChanged();
+ }
+
+ /**
+ * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
+ * depending on whether the user has selected 24-hour format.
+ *
+ * Calling this method does not schedule or unschedule the time ticker.
+ */
+ private void chooseFormat() {
+ chooseFormat(true);
+ }
+
+ /**
+ * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
+ * depending on whether the user has selected 24-hour format.
+ *
+ * @param handleTicker true if calling this method should schedule/unschedule the
+ * time ticker, false otherwise
+ */
+ private void chooseFormat(boolean handleTicker) {
+ final boolean format24Requested = is24HourModeEnabled();
+
+ if (format24Requested) {
+ mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR);
+ } else {
+ mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR);
+ }
+
+ boolean hadSeconds = mHasSeconds;
+ mHasSeconds = DateFormat.hasSeconds(mFormat);
+
+ if (handleTicker) {
+ if (hadSeconds != mHasSeconds) {
+ if (hadSeconds) getHandler().removeCallbacks(mTicker);
+ else mTicker.run();
+ }
+ }
+ }
+
+ /**
+ * Returns a if not null, else return b if not null, else return c.
+ */
+ private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
+ return a == null ? (b == null ? c : b) : a;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!mAttached) {
+ mAttached = true;
+
+ registerReceiver();
+ registerObserver();
+
+ createTime(mTimeZone);
+
+ if (mHasSeconds) {
+ mTicker.run();
+ } else {
+ onTimeChanged();
+ }
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mAttached) {
+ unregisterReceiver();
+ unregisterObserver();
+
+ getHandler().removeCallbacks(mTicker);
+
+ mAttached = false;
+ }
+ }
+
+ private void registerReceiver() {
+ final IntentFilter filter = new IntentFilter();
+
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+
+ getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+ }
+
+ private void registerObserver() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ }
+
+ private void unregisterReceiver() {
+ getContext().unregisterReceiver(mIntentReceiver);
+ }
+
+ private void unregisterObserver() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ resolver.unregisterContentObserver(mFormatChangeObserver);
+ }
+
+ private void onTimeChanged() {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ setText(DateFormat.format(mFormat, mTime));
+ }
+}
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 @@ interface IFaceLockInterface {
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 class LockPatternUtils {
*/
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..3f20ed1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -503,14 +503,16 @@
android:permissionGroupFlags="personalInfo"
android:priority="330" />
- <!-- Allows an application to access fine (e.g., GPS) location -->
+ <!-- Allows an app to access precise location from location sources such
+ as GPS, cell towers, and Wi-Fi. -->
<permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:permissionGroup="android.permission-group.LOCATION"
android:protectionLevel="dangerous"
android:label="@string/permlab_accessFineLocation"
android:description="@string/permdesc_accessFineLocation" />
- <!-- Allows an application to access coarse (e.g., Cell-ID, WiFi) location -->
+ <!-- Allows an app to access approximate location derived from network location
+ sources such as cell towers and Wi-Fi. -->
<permission android:name="android.permission.ACCESS_COARSE_LOCATION"
android:permissionGroup="android.permission-group.LOCATION"
android:protectionLevel="dangerous"
@@ -1901,6 +1903,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"
- />
-
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:layout_gravity="center">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ <include layout="@layout/keyguard_message_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
- <!-- 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">
+ <!-- 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"
+ >
- <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"
- />
+ <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"
- />
+ <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 d186c4a..186c8b3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3046,6 +3046,24 @@
<!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
<attr name="textAllCaps" format="boolean" />
</declare-styleable>
+ <declare-styleable name="TextClock">
+ <!-- Specifies the formatting pattern used to show the time and/or date
+ in 12-hour mode. Please refer to {@link android.text.format.DateFormat}
+ for a complete description of accepted formatting patterns.
+ The default pattern is "h:mm aa". -->
+ <attr name="format12Hour" format="string"/>
+ <!-- Specifies the formatting pattern used to show the time and/or date
+ in 24-hour mode. Please refer to {@link android.text.format.DateFormat}
+ for a complete description of accepted formatting patterns.
+ The default pattern is "k:mm". -->
+ <attr name="format24Hour" format="string"/>
+ <!-- Specifies the time zone to use. When this attribute is specified, the
+ TextClock will ignore the time zone of the system. To use the user's
+ time zone, do not specify this attribute. The default value is the
+ user's time zone. Please refer to {@link java.util.TimeZone} for more
+ information about time zone ids. -->
+ <attr name="timeZone" format="string"/>
+ </declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
<declare-styleable name="TextView">
@@ -5798,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/config.xml b/core/res/res/values/config.xml
index 0890a18..148560a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -650,9 +650,9 @@
speech -->
<bool name="config_bluetooth_wide_band_speech">true</bool>
- <!-- Boolean indicating if current platform supports quick switch-on/off of
- Bluetooth Module -->
- <bool name="config_bluetooth_adapter_quick_switch">true</bool>
+ <!-- Boolean indicating if current platform need do one-time bluetooth address
+ re-validation -->
+ <bool name="config_bluetooth_address_validation">false</bool>
<!-- The default data-use polling period. -->
<integer name="config_datause_polling_period_sec">600</integer>
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/public.xml b/core/res/res/values/public.xml
index d7a480b..06d3110 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2020,6 +2020,9 @@
<public type="attr" name="permissionFlags" id="0x010103c7" />
<public type="attr" name="checkedTextViewStyle" id="0x010103c8" />
<public type="attr" name="showOnLockScreen" id="0x010103c9" />
+ <public type="attr" name="format12Hour" id="0x010103ca" />
+ <public type="attr" name="format24Hour" id="0x010103cb" />
+ <public type="attr" name="timeZone" id="0x010103cc" />
<public type="style" name="Widget.Holo.CheckedTextView" id="0x010301d9" />
<public type="style" name="Widget.Holo.Light.CheckedTextView" id="0x010301da" />
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..e820ace 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -245,7 +245,7 @@
<java-symbol type="bool" name="action_bar_embed_tabs_pre_jb" />
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
<java-symbol type="bool" name="config_allowActionMenuItemTextWithIcon" />
- <java-symbol type="bool" name="config_bluetooth_adapter_quick_switch" />
+ <java-symbol type="bool" name="config_bluetooth_address_validation" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
<java-symbol type="bool" name="config_cellBroadcastAppLinks" />
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
@@ -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 class ConnectivityManagerTestActivity extends Activity {
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 @@ public class ConnectivityManagerTestActivity extends Activity {
* @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.net.wifi.WifiManager;
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 @@ public class WifiStressTest
// 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 @@ page.title=Publishing Checklist for Google Play
<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/docs/html/guide/google/play/expansion-files.jd b/docs/html/guide/google/play/expansion-files.jd
index 750e958..f5cda06 100644
--- a/docs/html/guide/google/play/expansion-files.jd
+++ b/docs/html/guide/google/play/expansion-files.jd
@@ -421,7 +421,7 @@ policy, which captures the expansion file names, sizes, and URLs from the licens
<p>To use APK expansion files with your application and provide the best user experience with
minimal effort on your behalf, we recommend you use the Downloader Library that's included in the
-Google Market Apk Expansion package. This library downloads your expansion files in a
+Google Play APK Expansion Library package. This library downloads your expansion files in a
background service, shows a user notification with the download status, handles network
connectivity loss, resumes the download when possible, and more.</p>
@@ -450,8 +450,8 @@ application.</p>
<p>First, open the <a href="{@docRoot}sdk/exploring.html">Android SDK Manager</a>, expand
<em>Extras</em> and download:</p>
<ul>
- <li><em>Google Market Licensing package</em></li>
- <li><em>Google Market Apk Expansion package</em></li>
+ <li><em>Google Play Licensing Library package</em></li>
+ <li><em>Google Play APK Expansion Library package</em></li>
</ul>
<p>If you're using Eclipse, create a project for each library and add it to your app:</p>
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 2de6260..8026b7d 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -18,6 +18,7 @@ page.title=Notifications
<li><a href="#Actions">Notification actions</a></li>
<li><a href="#SimpleNotification">Creating a simple notification</a></li>
<li><a href="#ApplyStyle">Applying a big view style to a notification</a></li>
+ <li><a href="#Compatibility">Handling compatibility</a></li>
</ol>
</li>
<li><a href="#Managing">Managing Notifications</a>
@@ -91,18 +92,36 @@ page.title=Notifications
</p>
</div>
<p class="note">
- <strong>Note:</strong> This guide refers to the
+ <strong>Note:</strong> Except where noted, this guide refers to the
{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} class
in the version 4 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.
- The class {@link android.app.Notification.Builder Notification.Builder} was added in API
- level 11.
+ The class {@link android.app.Notification.Builder Notification.Builder} was added in Android
+ 3.0.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="NotificationUI">Notification Display Elements</h2>
<p>
- Notifications in the notification drawer appear in two main visual styles, normal view and
- big view.
+ Notifications in the notification drawer can appear in one of two visual styles, depending on
+ the version and the state of the drawer:
+</p>
+<dl>
+ <dt>
+ Normal view
+ </dt>
+ <dd>
+ The standard view of the notifications in the notification drawer.
+ </dd>
+ <dt>
+ Big view
+ </dt>
+ <dd>
+ A large view that's visible when the notification is expanded. Big view is part of the
+ expanded notification feature available as of Android 4.1.
+ </dd>
+</dl>
+<p>
+ These styles are described in the following sections.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="NormalNotify">Normal view</h3>
@@ -139,7 +158,7 @@ page.title=Notifications
<p>
A notification's big view appears only when the notification is expanded, which happens when the
notification is at the top of the notification drawer, or when the user expands the
- notification with a gesture.
+ notification with a gesture. Expanded notifications are available starting with Android 4.1.
</p>
<p>
The following screenshot shows an inbox-style notification:
@@ -246,10 +265,12 @@ page.title=Notifications
</p>
<p>
A notification can provide multiple actions. You should always define the action that's
- triggered when the user touches the notification; usually this action opens an
+ triggered when the user clicks the notification; usually this action opens an
{@link android.app.Activity} in your application. You can also add buttons to the notification
that perform additional actions such as snoozing an alarm or responding immediately to a text
- message.
+ message; this feature is available as of Android 4.1. If you use additional action buttons, you
+ must also make their functionality available in an {@link android.app.Activity} in your app; see
+ the section <a href="#Compatibility">Handling compatibility</a> for more details.
</p>
<p>
Inside a {@link android.app.Notification}, the action itself is defined by a
@@ -257,22 +278,22 @@ page.title=Notifications
an {@link android.app.Activity} in your application. To associate the
{@link android.app.PendingIntent} with a gesture, call the appropriate method of
{@link android.support.v4.app.NotificationCompat.Builder}. For example, if you want to start
- {@link android.app.Activity} when the user touches the notification text in
+ {@link android.app.Activity} when the user clicks the notification text in
the notification drawer, you add the {@link android.app.PendingIntent} by calling
{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
</p>
<p>
- Starting an {@link android.app.Activity} when the user touches the notification is the most
+ Starting an {@link android.app.Activity} when the user clicks the notification is the most
common action scenario. You can also start an {@link android.app.Activity} when the user
- dismisses an {@link android.app.Activity}, and you can start an {@link android.app.Activity}
- from an action button. To learn more, read the reference guide for
+ dismisses an {@link android.app.Activity}. In Android 4.1 and later, you can start an
+ {@link android.app.Activity} from an action button. To learn more, read the reference guide for
{@link android.support.v4.app.NotificationCompat.Builder}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="SimpleNotification">Creating a simple notification</h3>
<p>
The following snippet illustrates a simple notification that specifies an activity to open when
- the user touches the notification. Notice that the code creates a
+ the user clicks the notification. Notice that the code creates a
{@link android.support.v4.app.TaskStackBuilder} object and uses it to create the
{@link android.app.PendingIntent} for the action. This pattern is explained in more detail
in the section <a href="#NotificationResponse">
@@ -317,6 +338,11 @@ mNotificationManager.notify(mId, mBuilder.build());
Builder.setStyle()} with a big view style object as its argument.
</p>
<p>
+ Remember that expanded notifications are not available on platforms prior to Android 4.1. To
+ learn how to handle notifications for Android 4.1 and for earlier platforms, read the
+ section <a href="#Compatibility">Handling compatibility</a>.
+</p>
+<p>
For example, the following code snippet demonstrates how to alter the notification created
in the previous snippet to use the Inbox big view style:
</p>
@@ -341,6 +367,47 @@ mBuilder.setStyle(inBoxStyle);
...
// Issue the notification here.
</pre>
+<h3 id="Compatibility">Handling compatibility</h3>
+<p>
+ Not all notification features are available for a particular version, even though
+ the methods to set them are in the support library class
+ {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
+ For example, action buttons, which depend on expanded notifications, only appear on Android
+ 4.1 and higher, because expanded notifications themselves are only available on
+ Android 4.1 and higher.
+</p>
+<p>
+ To ensure the best compatibility, create notifications with
+ {@link android.support.v4.app.NotificationCompat NotificationCompat} and its subclasses,
+ particularly {@link android.support.v4.app.NotificationCompat.Builder
+ NotificationCompat.Builder}. In addition, follow this process when you implement a notification:
+</p>
+<ol>
+ <li>
+ Provide all of the notification's functionality to all users, regardless of the version
+ they're using. To do this, verify that all of the functionality is available from an
+ {@link android.app.Activity} in your app. You may want to add a new
+ {@link android.app.Activity} to do this.
+ <p>
+ For example, if you want to use
+ {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} to
+ provide a control that stops and starts media playback, first implement this
+ control in an {@link android.app.Activity} in your app.
+ </p>
+ </li>
+ <li>
+ Ensure that all users can get to the functionality in the {@link android.app.Activity},
+ by having it start when users click the notification. To do this,
+ create a {@link android.app.PendingIntent} for the {@link android.app.Activity}. Call
+ {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+ setContentIntent()} to add the {@link android.app.PendingIntent} to the notification.
+ </li>
+ <li>
+ Now add the expanded notification features you want to use to the notification. Remember
+ that any functionality you add also has to be available in the {@link android.app.Activity}
+ that starts when users click the notification.
+ </li>
+</ol>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="Managing">Managing Notifications</h2>
@@ -355,6 +422,10 @@ mBuilder.setStyle(inBoxStyle);
"stacking" the notification; it's described in more detail in the
<a href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design guide.
</p>
+<p class="note">
+ <strong>Note:</strong> This Gmail feature requires the "inbox" big view style, which is
+ part of the expanded notification feature available starting in Android 4.1.
+</p>
<p>
The following section describes how to update notifications and also how to remove them.
</p>
@@ -417,7 +488,7 @@ numMessages = 0;
the notification can be cleared).
</li>
<li>
- The user touches the notification, and you called
+ The user clicks the notification, and you called
{@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} when
you created the notification.
</li>
@@ -452,7 +523,7 @@ numMessages = 0;
start a fresh task, and provide the {@link android.app.PendingIntent} with a back stack
that reproduces the application's normal <i>Back</i> behavior.
<p>
- Notifications from the Gmail app demonstrate this. When you touch a notification for
+ Notifications from the Gmail app demonstrate this. When you click a notification for
a single email message, you see the message itself. Touching <b>Back</b> takes you
backwards through Gmail to the Home screen, just as if you had entered Gmail from the
Home screen rather than entering it from a notification.
@@ -489,7 +560,7 @@ numMessages = 0;
Define your application's {@link android.app.Activity} hierarchy in the manifest.
<ol style="list-style-type: lower-alpha;">
<li>
- Add support for API versions 15 and earlier. To do this, specify the parent of the
+ Add support for Android 4.0.3 and earlier. To do this, specify the parent of the
{@link android.app.Activity} you're starting by adding a
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
element as the child of the
@@ -507,7 +578,7 @@ numMessages = 0;
</p>
</li>
<li>
- Also add support for API versions 16 and later. To do this, add the
+ Also add support for Android 4.1 and later. To do this, add the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code>
attribute to the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
@@ -738,9 +809,14 @@ mNotificationManager.notify(id, builder.build());
{@link android.widget.ProgressBar} class.
</p>
<p>
- To use a progress indicator, call
- {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. The
- determinate and indeterminate forms are described in the following sections.
+ To use a progress indicator on platforms starting with Android 4.0, call
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. For
+ previous versions, you must create your own custom notification layout that
+ includes a {@link android.widget.ProgressBar} view.
+</p>
+<p>
+ The following sections describe how to display progress in a notification using
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="FixedProgress">Displaying a fixed-duration progress indicator</h3>
@@ -872,6 +948,10 @@ mNotifyManager.notify(0, mBuilder.build());
{@link android.widget.RemoteViews} defined in a XML layout file.
</p>
<p>
+ The height available for a custom notification layout depends on the notification view. Normal
+ view layouts are limited to 64 dp, and expanded view layouts are limited to 256 dp.
+</p>
+<p>
To define a custom notification layout, start by instantiating a
{@link android.widget.RemoteViews} object that inflates an XML layout file. Then,
instead of calling methods such as
@@ -911,8 +991,8 @@ mNotifyManager.notify(0, mBuilder.build());
<h4>Using style resources for custom notification text</h4>
<p>
Always use style resources for the text of a custom notification. The background color of the
- notification can vary across different devices and platform versions, and using style resources
- helps you account for this. Starting in API level 9, the system defined a style for the
- standard notification layout text. If you use the same style in applications that target API
- level 9 or higher, you'll ensure that your text is visible against the display background.
+ notification can vary across different devices and versions, and using style resources
+ helps you account for this. Starting in Android 2.3, the system defined a style for the
+ standard notification layout text. If you use the same style in applications that target Android
+ 2.3 or higher, you'll ensure that your text is visible against the display background.
</p>
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 @@ public class GradientDrawable extends Drawable {
return;
}
+ if (mRadius > 0 || mRadiusArray != null) {
+ mOpaque = false;
+ return;
+ }
+
if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) {
mOpaque = false;
return;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e2d7156..6787705 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2433,7 +2433,7 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto
}
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
- if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || p->getStrokeCap() != SkPaint::kButt_Cap) {
+ if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || p->getStrokeCap() != SkPaint::kButt_Cap || useCenter) {
mCaches.activeTexture(0);
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index b3e4a88..791d3d0 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -22,7 +22,7 @@ import android.os.Parcelable;
/**
* 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,7 +34,7 @@ public final class Geofence implements Parcelable {
private final float mRadius;
/**
- * Create a horizontal, circular geofence.
+ * Create a circular geofence (on a flat, horizontal plane).
*
* @param latitude latitude in degrees
* @param longitude longitude in degrees
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f057ebc..4025a7b 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -60,11 +60,19 @@ public class Location implements Parcelable {
public static final int FORMAT_SECONDS = 2;
/**
+ * Bundle key for a version of the location that has been fed through
+ * LocationFudger. Allows location providers to flag locations as being
+ * safe for use with ACCESS_COARSE_LOCATION permission.
+ *
* @hide
*/
public static final String EXTRA_COARSE_LOCATION = "coarseLocation";
/**
+ * Bundle key for a version of the location containing no GPS data.
+ * Allows location providers to flag locations as being safe to
+ * feed to LocationFudger.
+ *
* @hide
*/
public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
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 @@ public class LocationManager {
/**
* 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 @@ public class LocationManager {
/**
* 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/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index b0e5d2c..8a5a739 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -23,6 +23,8 @@ import java.io.PrintWriter;
import android.content.Context;
import android.location.ILocationManager;
import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -58,6 +60,21 @@ public abstract class LocationProviderBase {
private final ProviderProperties mProperties;
private final IBinder mBinder;
+ /**
+ * Bundle key for a version of the location containing no GPS data.
+ * Allows location providers to flag locations as being safe to
+ * feed to LocationFudger.
+ */
+ public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION;
+
+ /**
+ * Name of the Fused location provider.
+ *
+ * <p>This provider combines inputs for all possible location sources
+ * to provide the best possible Location fix.
+ */
+ public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
+
private final class Service extends ILocationProvider.Stub {
@Override
public void enable() {
diff --git a/packages/FusedLocation/Android.mk b/packages/FusedLocation/Android.mk
index 318782f..a81b9f1 100644
--- a/packages/FusedLocation/Android.mk
+++ b/packages/FusedLocation/Android.mk
@@ -23,5 +23,6 @@ LOCAL_JAVA_LIBRARIES := com.android.location.provider
LOCAL_PACKAGE_NAME := FusedLocation
LOCAL_CERTIFICATE := platform
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 87d56fd..60de79c 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -20,6 +20,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import com.android.location.provider.LocationProviderBase;
import com.android.location.provider.ProviderRequestUnbundled;
import android.content.Context;
@@ -29,6 +30,7 @@ import android.location.LocationManager;
import android.location.LocationRequest;
import android.os.Bundle;
import android.os.Looper;
+import android.os.Parcelable;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.Log;
@@ -41,6 +43,7 @@ public class FusionEngine implements LocationListener {
private static final String TAG = "FusedLocation";
private static final String NETWORK = LocationManager.NETWORK_PROVIDER;
private static final String GPS = LocationManager.GPS_PROVIDER;
+ private static final String FUSED = LocationProviderBase.FUSED_PROVIDER;
public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000; // 11 seconds
@@ -72,6 +75,7 @@ public class FusionEngine implements LocationListener {
mStats.get(GPS).available = mLocationManager.isProviderEnabled(GPS);
mStats.put(NETWORK, new ProviderStats());
mStats.get(NETWORK).available = mLocationManager.isProviderEnabled(NETWORK);
+
}
public void init(Callback callback) {
@@ -226,10 +230,24 @@ public class FusionEngine implements LocationListener {
} else {
mFusedLocation = new Location(mNetworkLocation);
}
+ mFusedLocation.setProvider(FUSED);
if (mNetworkLocation != null) {
- mFusedLocation.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, mNetworkLocation);
+ // copy NO_GPS_LOCATION extra from mNetworkLocation into mFusedLocation
+ Bundle srcExtras = mNetworkLocation.getExtras();
+ if (srcExtras != null) {
+ Parcelable srcParcelable =
+ srcExtras.getParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION);
+ if (srcParcelable instanceof Location) {
+ Bundle dstExtras = mFusedLocation.getExtras();
+ if (dstExtras == null) {
+ dstExtras = new Bundle();
+ mFusedLocation.setExtras(dstExtras);
+ }
+ dstExtras.putParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION,
+ (Location) srcParcelable);
+ }
+ }
}
- mFusedLocation.setProvider(LocationManager.FUSED_PROVIDER);
mCallback.reportLocation(mFusedLocation);
}
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 @@ class QuickSettings {
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 @@ class QuickSettings {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mForceStatusBar = false;
@@ -2928,12 +2939,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public int finishPostLayoutPolicyLw() {
int changes = 0;
boolean topIsFullscreen = false;
@@ -2992,8 +3009,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
? 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (mKeyguardMediator.isShowing()) {
mHandler.post(new Runnable() {
+ @Override
public void run() {
mKeyguardMediator.keyguardDone(false, false);
}
@@ -3071,7 +3093,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
| 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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.content.pm.PackageManager.NameNotFoundException;
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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
mCallbacks = callbacks;
mActivityLauncher = activityLauncher;
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
public static CameraWidgetFrame create(Context context, Callbacks callbacks,
@@ -141,16 +146,22 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
}
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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
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 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
scaleX, scaleY,
startCenter, finishCenter));
+ enableWindowExitAnimation(false);
animate()
.scaleX(scale)
.scaleY(scale)
@@ -305,11 +317,27 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli
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 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
}
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 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
}
+ 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.AppWidgetHost;
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.View;
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 @@ public class KeyguardHostView extends KeyguardViewBase {
// 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 @@ public class KeyguardHostView extends KeyguardViewBase {
private KeyguardViewStateManager mViewStateManager;
private Rect mTempRect = new Rect();
- private int mTransportState = TRANSPORT_GONE;
/*package*/ interface TransportCallback {
void onListenerDetached();
@@ -144,7 +141,7 @@ public class KeyguardHostView extends KeyguardViewBase {
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 @@ public class KeyguardHostView extends KeyguardViewBase {
@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 @@ public class KeyguardHostView extends KeyguardViewBase {
addDefaultWidgets();
addWidgetsFromSettings();
+ mSwitchPageRunnable.run();
- mViewStateManager = new KeyguardViewStateManager();
SlidingChallengeLayout slider =
(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
if (slider != null) {
@@ -217,7 +216,6 @@ public class KeyguardHostView extends KeyguardViewBase {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mAppWidgetHost.startListening();
- post(mSwitchPageRunnable);
}
@Override
@@ -676,13 +674,10 @@ public class KeyguardHostView extends KeyguardViewBase {
// 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 @@ public class KeyguardHostView extends KeyguardViewBase {
@Override
LockPatternUtils getLockPatternUtils() {
return mLockPatternUtils;
- }};
+ }
+ };
private void addDefaultWidgets() {
LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -888,14 +884,22 @@ public class KeyguardHostView extends KeyguardViewBase {
@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 @@ public class KeyguardHostView extends KeyguardViewBase {
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 @@ public class KeyguardHostView extends KeyguardViewBase {
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 @@ public class KeyguardHostView extends KeyguardViewBase {
saveStickyWidgetIndex();
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
- ss.transportState = mTransportState;
+ ss.transportState = mViewStateManager.getTransportState();
return ss;
}
@@ -1040,7 +1113,7 @@ public class KeyguardHostView extends KeyguardViewBase {
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
- mTransportState = ss.transportState;
+ mViewStateManager.setTransportState(ss.transportState);
post(mSwitchPageRunnable);
}
@@ -1054,12 +1127,14 @@ public class KeyguardHostView extends KeyguardViewBase {
}
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 @@ public class KeyguardHostView extends KeyguardViewBase {
// 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 @@ public class KeyguardHostView extends KeyguardViewBase {
}
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 @@ public class KeyguardHostView extends KeyguardViewBase {
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 @@ class KeyguardMessageArea extends TextView {
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 @@ class KeyguardMessageArea extends TextView {
public void run() {
mMessage = null;
mShowingMessage = false;
- update();
+ if (mShowingBouncer) {
+ hideMessage(FADE_DURATION, true);
+ } else {
+ update();
+ }
}
};
@@ -103,6 +114,18 @@ class KeyguardMessageArea extends TextView {
}
@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 @@ class KeyguardMessageArea extends TextView {
}
public void securityMessageChanged() {
+ setAlpha(1f);
mShowingMessage = true;
update();
mHandler.removeCallbacks(mClearMessageRunnable);
@@ -212,4 +236,23 @@ class KeyguardMessageArea extends TextView {
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 @@ public class KeyguardPINView extends KeyguardAbsKeyInputView
}
@Override
+ protected int getPasswordTextViewId() {
+ return R.id.pinEntry;
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -59,6 +64,7 @@ public class KeyguardPINView extends KeyguardAbsKeyInputView
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 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
@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 class KeyguardSecurityContainer extends FrameLayout {
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 @@ class KeyguardStatusViewManager implements SecurityMessageDisplay {
}
@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.util.Log;
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 @@ import java.lang.ref.WeakReference;
/**
* 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 @@ public class KeyguardTransportControlView extends KeyguardWidgetFrame implements
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 @@ public class KeyguardViewManager {
private FrameLayout mKeyguardHost;
private KeyguardHostView mKeyguardView;
+ private boolean mScreenOn = false;
private LockPatternUtils mLockPatternUtils;
public interface ShowListener {
@@ -302,6 +303,7 @@ public class KeyguardViewManager {
public synchronized void onScreenTurnedOff() {
if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
+ mScreenOn = false;
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOff();
}
@@ -310,6 +312,7 @@ public class KeyguardViewManager {
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 @@ public class KeyguardViewManager {
}
/**
+ * 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 @@ public class KeyguardViewMediator {
}
/**
- * 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 @@ public class KeyguardViewMediator {
}
/**
+ * 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 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
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 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
return false;
}
+ public boolean isChallengeOverlapping() {
+ if (mChallengeLayout != null) {
+ return mChallengeLayout.isChallengeOverlapping();
+ }
+ return false;
+ }
+
public void setSecurityViewContainer(KeyguardSecurityView container) {
mKeyguardSecurityContainer = container;
}
@@ -79,6 +93,14 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
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 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle
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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
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 @@ public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
}
}
}
+
+ 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 @@ public class KeyguardWidgetFrame extends FrameLayout {
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.animation.TimeInterpolator;
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.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.internal.R;
-
import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
@@ -46,7 +48,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
}
- // 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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
if (mViewStateManager != null) {
mViewStateManager.onPageBeginMoving();
}
- showOutlinesAndSidePages();
+ if (!isReordering(false)) {
+ showOutlinesAndSidePages();
+ }
userActivity();
}
@@ -281,17 +319,22 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
void showOutlinesAndSidePages() {
- enablePageLayers();
animateOutlinesAndSidePages(true);
}
@@ -447,7 +493,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
showOutlinesAndSidePages();
} else {
// The layout hints depend on layout being run once
- mShowHintsOnLayout = true;
+ showHintsAfterLayout = true;
}
}
@@ -458,16 +504,17 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
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 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
@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 class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
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 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
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 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
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 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
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 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
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.SpannableStringBuilder;
import android.text.style.TextAppearanceSpan;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Button;
import android.widget.TextView;
@@ -72,6 +74,7 @@ public class NumPadKey extends Button {
setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0));
setOnClickListener(mListener);
+ setOnHoverListener(new LiftToActivateListener(context));
mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
@@ -113,4 +116,45 @@ public class NumPadKey extends Button {
| HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
}
+
+ /**
+ * Hover listener that implements lift-to-activate interaction for
+ * accessibility. May be added to multiple views.
+ */
+ static class LiftToActivateListener implements View.OnHoverListener {
+ /** Manager used to query accessibility enabled state. */
+ private final AccessibilityManager mAccessibilityManager;
+
+ public LiftToActivateListener(Context context) {
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ }
+
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ // When touch exploration is turned on, lifting a finger while
+ // inside the view bounds should perform a click action.
+ if (mAccessibilityManager.isEnabled()
+ && mAccessibilityManager.isTouchExplorationEnabled()) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ // Lift-to-type temporarily disables double-tap
+ // activation.
+ v.setClickable(false);
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+ if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
+ && (x < v.getWidth() - v.getPaddingRight())
+ && (y < v.getHeight() - v.getPaddingBottom())) {
+ v.performClick();
+ }
+ v.setClickable(true);
+ break;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
// "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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// 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 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
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 interface SecurityMessageDisplay {
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
mHandleAnimation.start();
}
- void animateFrame(boolean visible, boolean full) {
+ void animateFrame(final boolean visible, final boolean full) {
if (mFrameDrawable == null) return;
- if (mFrameAnimation != null) {
+ final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f;
+ if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) {
mFrameAnimation.cancel();
- mFrameAnimation = null;
+ mFrameAnimationTarget = Float.MIN_VALUE;
}
- final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f;
- if (targetAlpha == mFrameAlpha) {
+ 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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
void completeChallengeScroll() {
setChallengeShowing(mChallengeOffset != 0);
setScrollState(SCROLL_STATE_IDLE);
+ mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
}
void setScrimView(View scrim) {
@@ -461,7 +497,22 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
@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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
mVelocityTracker.addMovement(ev);
- //Log.v(TAG, "onIntercept: " + ev);
-
final int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -518,13 +576,15 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
mActivePointerId = ev.getPointerId(i);
mGestureStartChallengeBottom = getChallengeBottom();
mDragging = true;
+ mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
break;
}
}
@@ -631,6 +692,52 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
/**
+ * 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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
// 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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
// 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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
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 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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 class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
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/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 6ff33d7..69ccbc7 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -53,6 +53,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
private static final String EXTRA_ACTION="action";
+ private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
@@ -174,7 +175,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
//Enable
if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
enableHelper();
- } else if (!isNameAndAddressSet()) {
+ }
+
+ if (!isNameAndAddressSet()) {
//Sync the Bluetooth name and address from the Bluetooth Adapter
if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
getNameAndAddress();
@@ -222,11 +225,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
*/
private void loadStoredNameAndAddress() {
if (DBG) Log.d(TAG, "Loading stored name and address");
+ if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_address_validation) &&
+ Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
+ // if the valid flag is not set, don't load the address and name
+ if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
+ return;
+ }
mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
- if (mName == null || mAddress == null) {
- if (DBG) Log.d(TAG, "Name or address not cached...");
- }
+ if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
/**
@@ -249,6 +257,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
}
+
+ if ((name != null) && (address != null)) {
+ Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
+ }
}
public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
@@ -560,8 +572,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
break;
}
case MESSAGE_SAVE_NAME_AND_ADDRESS: {
+ boolean unbind = false;
if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
synchronized(mConnection) {
+ if (!mEnable && mBluetooth != null) {
+ try {
+ mBluetooth.enable();
+ } catch (RemoteException e) {
+ Log.e(TAG,"Unable to call enable()",e);
+ }
+ }
+ }
+ if (mBluetooth != null) waitForOnOff(true, false);
+ synchronized(mConnection) {
if (mBluetooth != null) {
String name = null;
String address = null;
@@ -575,7 +598,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (name != null && address != null) {
storeNameAndAddress(name,address);
if (mConnection.isGetNameAddressOnly()) {
- unbindAndFinish();
+ unbind = true;
}
} else {
if (msg.arg1 < MAX_SAVE_RETRIES) {
@@ -586,10 +609,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} else {
Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
if (mConnection.isGetNameAddressOnly()) {
- unbindAndFinish();
+ unbind = true;
}
}
}
+ if (!mEnable) {
+ try {
+ mBluetooth.disable();
+ } catch (RemoteException e) {
+ Log.e(TAG,"Unable to call disable()",e);
+ }
+ }
} else {
// rebind service by Request GET NAME AND ADDRESS
// if service is unbinded by disable or
@@ -598,6 +628,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mHandler.sendMessage(getMsg);
}
}
+ if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
+ if (unbind) {
+ unbindAndFinish();
+ }
break;
}
case MESSAGE_ENABLE:
@@ -677,14 +711,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
//Inform BluetoothAdapter instances that service is up
sendBluetoothServiceUpCallback();
- //Check if name and address is loaded if not get it first.
- if (!isNameAndAddressSet()) {
- try {
- storeNameAndAddress(mBluetooth.getName(),
- mBluetooth.getAddress());
- } catch (RemoteException e) {Log.e(TAG, "", e);};
- }
-
//Do enable request
try {
if (mQuietEnable == false) {
@@ -873,14 +899,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
sendBluetoothServiceUpCallback();
}
- //Check if name and address is loaded if not get it first.
- if (!isNameAndAddressSet()) {
- try {
- if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
- storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
- } catch (RemoteException e) {Log.e(TAG, "", e);};
- }
-
//Enable bluetooth
try {
if (!mQuietEnable) {
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 @@ public class NotificationManagerService extends INotificationManager.Stub
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 class NotificationManagerService extends INotificationManager.Stub
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 @@ public class NotificationManagerService extends INotificationManager.Stub
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 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
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 @@ public final class ActivityManagerService extends ActivityManagerNative
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/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 2445b98..ca94d04 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -279,22 +279,22 @@ public class AppWindowAnimator {
return isAnimating;
}
- void dump(PrintWriter pw, String prefix) {
- if (freezingScreen) {
- pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen);
- }
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+ pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
+ pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
+ pw.print(" allDrawn="); pw.print(allDrawn);
+ pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
if (animating || animation != null) {
pw.print(prefix); pw.print("animating="); pw.print(animating);
- pw.print(" animation="); pw.println(animation);
+ pw.print(" animInitialized="); pw.println(animInitialized);
+ pw.print(prefix); pw.print("animation="); pw.println(animation);
}
if (hasTransformation) {
pw.print(prefix); pw.print("XForm: ");
transformation.printShortString(pw);
pw.println();
}
- if (animLayerAdjustment != 0) {
- pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
- }
if (thumbnail != null) {
pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
pw.print(" x="); pw.print(thumbnailX);
@@ -304,6 +304,11 @@ public class AppWindowAnimator {
pw.print(prefix); pw.print("thumbnailTransformation=");
pw.println(thumbnailTransformation.toShortString());
}
+ for (int i=0; i<mAllAppWinAnimators.size(); i++) {
+ WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
+ pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
+ pw.print(": "); pw.println(wanim);
+ }
}
// This is an animation that does nothing: it just immediately finishes
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 9a62482..c8d9cc3 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -18,12 +18,14 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.TimeUtils;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
import com.android.server.wm.WindowManagerService.AppWindowAnimParams;
+import com.android.server.wm.WindowManagerService.LayoutFields;
import com.android.server.wm.WindowManagerService.LayoutToAnimatorParams;
import java.io.PrintWriter;
@@ -197,6 +199,15 @@ public class WindowAnimator {
mWallpaperTokens = new ArrayList<WindowToken>(layoutToAnim.mWallpaperTokens);
}
+ if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) {
+ if (mWallpaperTarget != layoutToAnim.mWallpaperTarget
+ || mLowerWallpaperTarget != layoutToAnim.mLowerWallpaperTarget
+ || mUpperWallpaperTarget != layoutToAnim.mUpperWallpaperTarget) {
+ Slog.d(TAG, "Updating anim wallpaper: target=" + mWallpaperTarget
+ + " lower=" + mLowerWallpaperTarget + " upper="
+ + mUpperWallpaperTarget);
+ }
+ }
mWallpaperTarget = layoutToAnim.mWallpaperTarget;
mWpAppAnimator = mWallpaperTarget == null
? null : mWallpaperTarget.mAppToken == null
@@ -735,46 +746,144 @@ public class WindowAnimator {
return dimParams != null && dimParams.mDimWinAnimator == winAnimator;
}
+ static String bulkUpdateParamsToString(int bulkUpdateParams) {
+ StringBuilder builder = new StringBuilder(128);
+ if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
+ builder.append(" UPDATE_ROTATION");
+ }
+ if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
+ builder.append(" WALLPAPER_MAY_CHANGE");
+ }
+ if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
+ builder.append(" FORCE_HIDING_CHANGED");
+ }
+ if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
+ builder.append(" ORIENTATION_CHANGE_COMPLETE");
+ }
+ if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+ builder.append(" TURN_ON_SCREEN");
+ }
+ return builder.toString();
+ }
+
public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
- if (dumpAll) {
- if (mWindowDetachedWallpaper != null) {
- pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
- pw.println(mWindowDetachedWallpaper);
- }
- pw.print(prefix); pw.print("mAnimTransactionSequence=");
- pw.print(mAnimTransactionSequence);
- pw.println(" mForceHiding=" + forceHidingToString());
- for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
- pw.print(prefix); pw.print("DisplayContentsAnimator #");
- pw.println(mDisplayContentsAnimators.keyAt(i));
- DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
- final String subPrefix = " " + prefix;
- final String subSubPrefix = " " + subPrefix;
- if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
- pw.println(subPrefix + "mWindowAnimationBackgroundSurface:");
- displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
- }
- if (displayAnimator.mDimAnimator != null) {
- pw.println(subPrefix + "mDimAnimator:");
- displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
- } else {
- pw.println(subPrefix + "no DimAnimator ");
- }
- if (displayAnimator.mDimParams != null) {
- pw.println(subPrefix + "mDimParams:");
- displayAnimator.mDimParams.printTo(subSubPrefix, pw);
+ final String subPrefix = " " + prefix;
+ final String subSubPrefix = " " + subPrefix;
+
+ boolean needSep = false;
+ if (mAppAnimators.size() > 0) {
+ needSep = true;
+ pw.println(" App Animators:");
+ for (int i=mAppAnimators.size()-1; i>=0; i--) {
+ AppWindowAnimator anim = mAppAnimators.get(i);
+ pw.print(prefix); pw.print("App Animator #"); pw.print(i);
+ pw.print(' '); pw.print(anim);
+ if (dumpAll) {
+ pw.println(':');
+ anim.dump(pw, subPrefix, dumpAll);
} else {
- pw.println(subPrefix + "no DimParams ");
+ pw.println();
}
- if (displayAnimator.mScreenRotationAnimation != null) {
- pw.println(subPrefix + "mScreenRotationAnimation:");
- displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
+ }
+ }
+ if (mWallpaperTokens.size() > 0) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.print(prefix); pw.println("Wallpaper tokens:");
+ for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
+ WindowToken token = mWallpaperTokens.get(i);
+ pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
+ pw.print(' '); pw.print(token);
+ if (dumpAll) {
+ pw.println(':');
+ token.dump(pw, subPrefix);
} else {
- pw.print(subPrefix + "no ScreenRotationAnimation ");
+ pw.println();
}
}
+ }
+
+ if (needSep) {
pw.println();
}
+ for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
+ pw.print(prefix); pw.print("DisplayContentsAnimator #");
+ pw.print(mDisplayContentsAnimators.keyAt(i));
+ pw.println(":");
+ DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+ for (int j=0; j<displayAnimator.mWinAnimators.size(); j++) {
+ WindowStateAnimator wanim = displayAnimator.mWinAnimators.get(j);
+ pw.print(subPrefix); pw.print("Window #"); pw.print(j);
+ pw.print(": "); pw.println(wanim);
+ }
+ if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
+ if (dumpAll || displayAnimator.mWindowAnimationBackgroundSurface.mDimShown) {
+ pw.print(subPrefix); pw.println("mWindowAnimationBackgroundSurface:");
+ displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
+ }
+ }
+ if (displayAnimator.mDimAnimator != null) {
+ if (dumpAll || displayAnimator.mDimAnimator.mDimShown) {
+ pw.print(subPrefix); pw.println("mDimAnimator:");
+ displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
+ }
+ } else if (dumpAll) {
+ pw.print(subPrefix); pw.println("no DimAnimator ");
+ }
+ if (displayAnimator.mDimParams != null) {
+ pw.print(subPrefix); pw.println("mDimParams:");
+ displayAnimator.mDimParams.printTo(subSubPrefix, pw);
+ } else if (dumpAll) {
+ pw.print(subPrefix); pw.println("no DimParams ");
+ }
+ if (displayAnimator.mScreenRotationAnimation != null) {
+ pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
+ displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
+ } else if (dumpAll) {
+ pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
+ }
+ }
+
+ pw.println();
+
+ if (dumpAll) {
+ pw.print(prefix); pw.print("mAnimTransactionSequence=");
+ pw.print(mAnimTransactionSequence);
+ pw.print(" mForceHiding="); pw.println(forceHidingToString());
+ pw.print(prefix); pw.print("mCurrentTime=");
+ pw.println(TimeUtils.formatUptime(mCurrentTime));
+ pw.print(prefix); pw.print("mDw=");
+ pw.print(mDw); pw.print(" mDh="); pw.print(mDh);
+ pw.print(" mInnerDw="); pw.print(mInnerDw);
+ pw.print(" mInnerDh="); pw.println(mInnerDh);
+ }
+ if (mBulkUpdateParams != 0) {
+ pw.print(prefix); pw.print("mBulkUpdateParams=0x");
+ pw.print(Integer.toHexString(mBulkUpdateParams));
+ pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
+ }
+ if (mPendingActions != 0) {
+ pw.print(prefix); pw.print("mPendingActions=0x");
+ pw.println(Integer.toHexString(mPendingActions));
+ }
+ if (mWindowDetachedWallpaper != null) {
+ pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
+ pw.println(mWindowDetachedWallpaper);
+ }
+ pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
+ pw.print(prefix); pw.print("mWpAppAnimator="); pw.println(mWpAppAnimator);
+ if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
+ pw.print(prefix); pw.print("mLowerWallpaperTarget=");
+ pw.println(mLowerWallpaperTarget);
+ pw.print(prefix); pw.print("mUpperWallpaperTarget=");
+ pw.println(mUpperWallpaperTarget);
+ }
+ if (mUniverseBackground != null) {
+ pw.print(prefix); pw.print("mUniverseBackground="); pw.print(mUniverseBackground);
+ pw.print(" mAboveUniverseLayer="); pw.println(mAboveUniverseLayer);
+ }
}
void clearPendingActions() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 637f2de..137c8ee 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2773,7 +2773,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
}
mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+ if (DEBUG_LAYOUT) {
+ Slog.v(TAG, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
+ }
}
if (configChanged) {
@@ -8379,7 +8383,8 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
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();
@@ -10322,6 +10329,11 @@ public class WindowManagerService extends IWindowManager.Stub
mPolicy.dump(" ", pw, args);
}
+ void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
+ pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
+ mAnimator.dumpLocked(pw, " ", dumpAll);
+ }
+
void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
if (mTokenMap.size() > 0) {
@@ -10598,7 +10610,7 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
}
pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
- if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
+ if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
}
@@ -10682,8 +10694,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
- pw.println(" Window Animator:");
- mAnimator.dumpLocked(pw, " ", dumpAll);
+ pw.println(" mLayoutToAnim:");
+ pw.print(" mParamsModified="); pw.print(mLayoutToAnim.mParamsModified);
+ pw.print(" mAnimationScheduled="); pw.print(mLayoutToAnim.mAnimationScheduled);
+ pw.print(" mChanges=0x");
+ pw.println(Long.toHexString(mLayoutToAnim.mChanges));
+ pw.print(" mWallpaperTarget="); pw.println(mLayoutToAnim.mWallpaperTarget);
+ if (mLayoutToAnim.mLowerWallpaperTarget != null
+ || mLayoutToAnim.mUpperWallpaperTarget != null) {
+ pw.print(" mLowerWallpaperTarget=");
+ pw.println(mLayoutToAnim.mLowerWallpaperTarget);
+ pw.print(" mUpperWallpaperTarget=");
+ pw.println(mLayoutToAnim.mUpperWallpaperTarget);
+ }
+ for (int i=0; i<mLayoutToAnim.mWinAnimatorLists.size(); i++) {
+ pw.print(" Win Animator List #");
+ pw.print(mLayoutToAnim.mWinAnimatorLists.keyAt(i)); pw.println(":");
+ WinAnimatorList wanim = mLayoutToAnim.mWinAnimatorLists.valueAt(i);
+ for (int wi=0; wi<wanim.size(); wi++) {
+ pw.print(" "); pw.println(wanim.get(wi));
+ }
+ }
+ for (int i=0; i<mLayoutToAnim.mWallpaperTokens.size(); i++) {
+ pw.print(" Wallpaper Token #"); pw.print(i); pw.print(": ");
+ pw.println(mLayoutToAnim.mWallpaperTokens.get(i));
+ }
+ // XXX also need to print mDimParams and mAppWindowAnimParams. I am lazy.
}
}
@@ -10793,6 +10829,7 @@ public class WindowManagerService extends IWindowManager.Stub
pw.println(" cmd may be one of:");
pw.println(" l[astanr]: last ANR information");
pw.println(" p[policy]: policy state");
+ pw.println(" a[animator]: animator state");
pw.println(" s[essions]: active sessions");
pw.println(" t[okens]: token list");
pw.println(" w[indows]: window list");
@@ -10822,6 +10859,11 @@ public class WindowManagerService extends IWindowManager.Stub
dumpPolicyLocked(pw, args, true);
}
return;
+ } else if ("animator".equals(cmd) || "a".equals(cmd)) {
+ synchronized(mWindowMap) {
+ dumpAnimatorLocked(pw, args, true);
+ }
+ return;
} else if ("sessions".equals(cmd) || "s".equals(cmd)) {
synchronized(mWindowMap) {
dumpSessionsLocked(pw, true);
@@ -10867,6 +10909,11 @@ public class WindowManagerService extends IWindowManager.Stub
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
+ dumpAnimatorLocked(pw, args, dumpAll);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
dumpSessionsLocked(pw, dumpAll);
pw.println();
if (dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index c195f45..e1cc58f 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -250,7 +250,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// Used to improve performance of toString()
String mStringNameCache;
CharSequence mLastTitle;
- boolean mWasPaused;
+ boolean mWasExiting;
final WindowStateAnimator mWinAnimator;
@@ -282,7 +282,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
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) {
@@ -1206,7 +1206,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(" visible="); mLastVisibleInsets.printShortString(pw);
pw.println();
}
- mWinAnimator.dump(pw, prefix, dumpAll);
+ pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
+ mWinAnimator.dump(pw, prefix + " ", dumpAll);
if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
@@ -1241,9 +1242,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
@Override
public String toString() {
if (mStringNameCache == null || mLastTitle != mAttrs.getTitle()
- || mWasPaused != mToken.paused) {
+ || mWasExiting != mExiting) {
mLastTitle = mAttrs.getTitle();
- mWasPaused = mToken.paused;
+ mWasExiting = mExiting;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
+ " u" + UserHandle.getUserId(mSession.mUid)
+ " " + mLastTitle + (mExiting ? " EXITING}" : "}");
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 2bfefe1..85f087f 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1604,10 +1604,11 @@ class WindowStateAnimator {
@Override
public String toString() {
- StringBuffer sb = new StringBuffer("WindowStateAnimator (");
- sb.append(mWin.mLastTitle + "): ");
- sb.append("mSurface " + mSurface);
- sb.append(", mAnimation " + mAnimation);
+ StringBuffer sb = new StringBuffer("WindowStateAnimator{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(mWin.mAttrs.getTitle());
+ sb.append('}');
return sb.toString();
}
}