Merge "Moved setting the flag to suppress face unlock during a phone call" into jb-dev
diff --git a/api/16.txt b/api/16.txt
index 1a694a8..b8aeb39 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -3595,6 +3595,8 @@
   public class KeyguardManager {
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
+    method public boolean isKeyguardLocked();
+    method public boolean isKeyguardSecure();
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
@@ -6519,6 +6521,7 @@
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
+    field public static final java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -6794,7 +6797,7 @@
     field public static final int NAVIGATION_WHEEL = 4; // 0x4
     field public static final int ORIENTATION_LANDSCAPE = 2; // 0x2
     field public static final int ORIENTATION_PORTRAIT = 1; // 0x1
-    field public static final int ORIENTATION_SQUARE = 3; // 0x3
+    field public static final deprecated int ORIENTATION_SQUARE = 3; // 0x3
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LONG_MASK = 48; // 0x30
     field public static final int SCREENLAYOUT_LONG_NO = 16; // 0x10
@@ -6811,7 +6814,7 @@
     field public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; // 0x0
     field public static final int TOUCHSCREEN_FINGER = 3; // 0x3
     field public static final int TOUCHSCREEN_NOTOUCH = 1; // 0x1
-    field public static final int TOUCHSCREEN_STYLUS = 2; // 0x2
+    field public static final deprecated int TOUCHSCREEN_STYLUS = 2; // 0x2
     field public static final int TOUCHSCREEN_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_NIGHT_MASK = 48; // 0x30
     field public static final int UI_MODE_NIGHT_NO = 16; // 0x10
@@ -9242,7 +9245,6 @@
     method public int getMinimumWidth();
     method public abstract int getOpacity();
     method public boolean getPadding(android.graphics.Rect);
-    method public int getResolvedLayoutDirectionSelf();
     method public int[] getState();
     method public android.graphics.Region getTransparentRegion();
     method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -19690,6 +19692,7 @@
     method public static final android.content.Intent getVoiceDetailsIntent(android.content.Context);
     field public static final java.lang.String ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS";
     field public static final java.lang.String ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH";
+    field public static final java.lang.String ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE";
     field public static final java.lang.String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
     field public static final java.lang.String DETAILS_META_DATA = "android.speech.DETAILS";
     field public static final java.lang.String EXTRA_CALLING_PACKAGE = "calling_package";
@@ -19705,6 +19708,7 @@
     field public static final java.lang.String EXTRA_RESULTS = "android.speech.extra.RESULTS";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
+    field public static final java.lang.String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
@@ -22735,6 +22739,17 @@
     method public void onPrepareSubMenu(android.view.SubMenu);
   }
 
+  public final class Choreographer {
+    method public static android.view.Choreographer getInstance();
+    method public void postFrameCallback(android.view.Choreographer.FrameCallback);
+    method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
+    method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
+  }
+
+  public static abstract interface Choreographer.FrameCallback {
+    method public abstract void doFrame(long);
+  }
+
   public abstract interface CollapsibleActionView {
     method public abstract void onActionViewCollapsed();
     method public abstract void onActionViewExpanded();
@@ -24510,14 +24525,14 @@
   public class ViewDebug {
     ctor public ViewDebug();
     method public static void dumpCapturedView(java.lang.String, java.lang.Object);
-    method public static void startHierarchyTracing(java.lang.String, android.view.View);
-    method public static void startRecyclerTracing(java.lang.String, android.view.View);
-    method public static void stopHierarchyTracing();
-    method public static void stopRecyclerTracing();
-    method public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
-    method public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
-    field public static final boolean TRACE_HIERARCHY = false;
-    field public static final boolean TRACE_RECYCLER = false;
+    method public static deprecated void startHierarchyTracing(java.lang.String, android.view.View);
+    method public static deprecated void startRecyclerTracing(java.lang.String, android.view.View);
+    method public static deprecated void stopHierarchyTracing();
+    method public static deprecated void stopRecyclerTracing();
+    method public static deprecated void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
+    method public static deprecated void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
+    field public static final deprecated boolean TRACE_HIERARCHY = false;
+    field public static final deprecated boolean TRACE_RECYCLER = false;
   }
 
   public static abstract class ViewDebug.CapturedViewProperty implements java.lang.annotation.Annotation {
@@ -24529,7 +24544,7 @@
   public static abstract class ViewDebug.FlagToString implements java.lang.annotation.Annotation {
   }
 
-  public static final class ViewDebug.HierarchyTraceType extends java.lang.Enum {
+  public static final deprecated class ViewDebug.HierarchyTraceType extends java.lang.Enum {
     method public static android.view.ViewDebug.HierarchyTraceType valueOf(java.lang.String);
     method public static final android.view.ViewDebug.HierarchyTraceType[] values();
     enum_constant public static final android.view.ViewDebug.HierarchyTraceType BUILD_CACHE;
@@ -24545,7 +24560,7 @@
   public static abstract class ViewDebug.IntToString implements java.lang.annotation.Annotation {
   }
 
-  public static final class ViewDebug.RecyclerTraceType extends java.lang.Enum {
+  public static final deprecated class ViewDebug.RecyclerTraceType extends java.lang.Enum {
     method public static android.view.ViewDebug.RecyclerTraceType valueOf(java.lang.String);
     method public static final android.view.ViewDebug.RecyclerTraceType[] values();
     enum_constant public static final android.view.ViewDebug.RecyclerTraceType BIND_VIEW;
@@ -27326,7 +27341,7 @@
     field public int gravity;
   }
 
-  public class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
+  public deprecated class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
     ctor public Gallery(android.content.Context);
     ctor public Gallery(android.content.Context, android.util.AttributeSet);
     ctor public Gallery(android.content.Context, android.util.AttributeSet, int);
@@ -28617,8 +28632,6 @@
     method public void onEndBatchEdit();
     method public boolean onPreDraw();
     method public boolean onPrivateIMECommand(java.lang.String, android.os.Bundle);
-    method public void onResolvedLayoutDirectionReset();
-    method public void onResolvedTextDirectionChanged();
     method public void onRestoreInstanceState(android.os.Parcelable);
     method public android.os.Parcelable onSaveInstanceState();
     method protected void onSelectionChanged(int, int);
diff --git a/api/current.txt b/api/current.txt
index 1a694a8..b8aeb39 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3595,6 +3595,8 @@
   public class KeyguardManager {
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
+    method public boolean isKeyguardLocked();
+    method public boolean isKeyguardSecure();
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
@@ -6519,6 +6521,7 @@
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
+    field public static final java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -6794,7 +6797,7 @@
     field public static final int NAVIGATION_WHEEL = 4; // 0x4
     field public static final int ORIENTATION_LANDSCAPE = 2; // 0x2
     field public static final int ORIENTATION_PORTRAIT = 1; // 0x1
-    field public static final int ORIENTATION_SQUARE = 3; // 0x3
+    field public static final deprecated int ORIENTATION_SQUARE = 3; // 0x3
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LONG_MASK = 48; // 0x30
     field public static final int SCREENLAYOUT_LONG_NO = 16; // 0x10
@@ -6811,7 +6814,7 @@
     field public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; // 0x0
     field public static final int TOUCHSCREEN_FINGER = 3; // 0x3
     field public static final int TOUCHSCREEN_NOTOUCH = 1; // 0x1
-    field public static final int TOUCHSCREEN_STYLUS = 2; // 0x2
+    field public static final deprecated int TOUCHSCREEN_STYLUS = 2; // 0x2
     field public static final int TOUCHSCREEN_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_NIGHT_MASK = 48; // 0x30
     field public static final int UI_MODE_NIGHT_NO = 16; // 0x10
@@ -9242,7 +9245,6 @@
     method public int getMinimumWidth();
     method public abstract int getOpacity();
     method public boolean getPadding(android.graphics.Rect);
-    method public int getResolvedLayoutDirectionSelf();
     method public int[] getState();
     method public android.graphics.Region getTransparentRegion();
     method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -19690,6 +19692,7 @@
     method public static final android.content.Intent getVoiceDetailsIntent(android.content.Context);
     field public static final java.lang.String ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS";
     field public static final java.lang.String ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH";
+    field public static final java.lang.String ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE";
     field public static final java.lang.String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
     field public static final java.lang.String DETAILS_META_DATA = "android.speech.DETAILS";
     field public static final java.lang.String EXTRA_CALLING_PACKAGE = "calling_package";
@@ -19705,6 +19708,7 @@
     field public static final java.lang.String EXTRA_RESULTS = "android.speech.extra.RESULTS";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
     field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
+    field public static final java.lang.String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
     field public static final java.lang.String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
@@ -22735,6 +22739,17 @@
     method public void onPrepareSubMenu(android.view.SubMenu);
   }
 
+  public final class Choreographer {
+    method public static android.view.Choreographer getInstance();
+    method public void postFrameCallback(android.view.Choreographer.FrameCallback);
+    method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
+    method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
+  }
+
+  public static abstract interface Choreographer.FrameCallback {
+    method public abstract void doFrame(long);
+  }
+
   public abstract interface CollapsibleActionView {
     method public abstract void onActionViewCollapsed();
     method public abstract void onActionViewExpanded();
@@ -24510,14 +24525,14 @@
   public class ViewDebug {
     ctor public ViewDebug();
     method public static void dumpCapturedView(java.lang.String, java.lang.Object);
-    method public static void startHierarchyTracing(java.lang.String, android.view.View);
-    method public static void startRecyclerTracing(java.lang.String, android.view.View);
-    method public static void stopHierarchyTracing();
-    method public static void stopRecyclerTracing();
-    method public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
-    method public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
-    field public static final boolean TRACE_HIERARCHY = false;
-    field public static final boolean TRACE_RECYCLER = false;
+    method public static deprecated void startHierarchyTracing(java.lang.String, android.view.View);
+    method public static deprecated void startRecyclerTracing(java.lang.String, android.view.View);
+    method public static deprecated void stopHierarchyTracing();
+    method public static deprecated void stopRecyclerTracing();
+    method public static deprecated void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
+    method public static deprecated void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
+    field public static final deprecated boolean TRACE_HIERARCHY = false;
+    field public static final deprecated boolean TRACE_RECYCLER = false;
   }
 
   public static abstract class ViewDebug.CapturedViewProperty implements java.lang.annotation.Annotation {
@@ -24529,7 +24544,7 @@
   public static abstract class ViewDebug.FlagToString implements java.lang.annotation.Annotation {
   }
 
-  public static final class ViewDebug.HierarchyTraceType extends java.lang.Enum {
+  public static final deprecated class ViewDebug.HierarchyTraceType extends java.lang.Enum {
     method public static android.view.ViewDebug.HierarchyTraceType valueOf(java.lang.String);
     method public static final android.view.ViewDebug.HierarchyTraceType[] values();
     enum_constant public static final android.view.ViewDebug.HierarchyTraceType BUILD_CACHE;
@@ -24545,7 +24560,7 @@
   public static abstract class ViewDebug.IntToString implements java.lang.annotation.Annotation {
   }
 
-  public static final class ViewDebug.RecyclerTraceType extends java.lang.Enum {
+  public static final deprecated class ViewDebug.RecyclerTraceType extends java.lang.Enum {
     method public static android.view.ViewDebug.RecyclerTraceType valueOf(java.lang.String);
     method public static final android.view.ViewDebug.RecyclerTraceType[] values();
     enum_constant public static final android.view.ViewDebug.RecyclerTraceType BIND_VIEW;
@@ -27326,7 +27341,7 @@
     field public int gravity;
   }
 
-  public class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
+  public deprecated class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
     ctor public Gallery(android.content.Context);
     ctor public Gallery(android.content.Context, android.util.AttributeSet);
     ctor public Gallery(android.content.Context, android.util.AttributeSet, int);
@@ -28617,8 +28632,6 @@
     method public void onEndBatchEdit();
     method public boolean onPreDraw();
     method public boolean onPrivateIMECommand(java.lang.String, android.os.Bundle);
-    method public void onResolvedLayoutDirectionReset();
-    method public void onResolvedTextDirectionChanged();
     method public void onRestoreInstanceState(android.os.Parcelable);
     method public android.os.Parcelable onSaveInstanceState();
     method protected void onSelectionChanged(int, int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8cd8900..cb53422 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -645,10 +645,6 @@
         String process = null;
         
         String cmd = nextArgRequired();
-        if ("looper".equals(cmd)) {
-            cmd = nextArgRequired();
-            profileType = 1;
-        }
 
         if ("start".equals(cmd)) {
             start = true;
@@ -1295,8 +1291,8 @@
                 "       am broadcast <INTENT>\n" +
                 "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
                 "               [--no-window-animation] <COMPONENT>\n" +
-                "       am profile [looper] start <PROCESS> <FILE>\n" +
-                "       am profile [looper] stop [<PROCESS>]\n" +
+                "       am profile start <PROCESS> <FILE>\n" +
+                "       am profile stop [<PROCESS>]\n" +
                 "       am dumpheap [flags] <PROCESS> <FILE>\n" +
                 "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
                 "       am clear-debug-app\n" +
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 044c0c2..ebe2b98 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -59,9 +59,13 @@
  * An accessibility is declared as any other service in an AndroidManifest.xml but it
  * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
  * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Following is an example declaration:
+ * ignore the accessibility service. Additionally an accessibility service must request
+ * "android.permission.BIND_ACCESSIBILITY_SERVICE" permission to ensure that only the system
+ * can bind to it. Failure to declare this intent will cause the system to ignore the
+ * accessibility service. Following is an example declaration:
  * </p>
- * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
+ * <pre> &lt;service android:name=".MyAccessibilityService"
+ *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE&gt;
  *     &lt;intent-filter&gt;
  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
  *     &lt;/intent-filter&gt;
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 136c68c..291e75e 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -119,8 +119,6 @@
                     + savedInstanceState + ")");
         }
 
-        setContentView(R.layout.choose_type_and_account);
-
         if (savedInstanceState != null) {
             mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
             mExistingAccounts =
@@ -164,14 +162,29 @@
             }
         }
 
-        // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
-        Set<String> setOfAllowableAccountTypes = null;
-        final String[] validAccountTypes =
+        // An account type is relevant iff it is allowed by the caller and supported by the account
+        // manager.
+        Set<String> setOfRelevantAccountTypes = null;
+        final String[] allowedAccountTypes =
                 intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
-        if (validAccountTypes != null) {
-            setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.length);
-            for (String type : validAccountTypes) {
-                setOfAllowableAccountTypes.add(type);
+        if (allowedAccountTypes != null) {
+
+            setOfRelevantAccountTypes = new HashSet<String>(allowedAccountTypes.length);
+            Set<String> setOfAllowedAccountTypes = new HashSet<String>(allowedAccountTypes.length);
+            for (String type : allowedAccountTypes) {
+                setOfAllowedAccountTypes.add(type);
+            }
+
+            AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
+            Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
+            for (AuthenticatorDescription desc : descs) {
+                supportedAccountTypes.add(desc.type);
+            }
+
+            for (String acctType : setOfAllowedAccountTypes) {
+                if (supportedAccountTypes.contains(acctType)) {
+                    setOfRelevantAccountTypes.add(acctType);
+                }
             }
         }
 
@@ -185,8 +198,8 @@
                     && !setOfAllowableAccounts.contains(account)) {
                 continue;
             }
-            if (setOfAllowableAccountTypes != null
-                    && !setOfAllowableAccountTypes.contains(account.type)) {
+            if (setOfRelevantAccountTypes != null
+                    && !setOfRelevantAccountTypes.contains(account.type)) {
                 continue;
             }
             mAccountInfos.add(new AccountInfo(account,
@@ -194,30 +207,15 @@
                     account.equals(selectedAccount)));
         }
 
-        // there is more than one allowable account. initialize the list adapter to allow
-        // the user to select an account.
-        ListView list = (ListView) findViewById(android.R.id.list);
-        list.setAdapter(new AccountArrayAdapter(this,
-                android.R.layout.simple_list_item_1, mAccountInfos));
-        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
-                onListItemClick((ListView)parent, v, position, id);
-            }
-        });
-
-        // set the listener for the addAccount button
-        Button addAccountButton = (Button) findViewById(R.id.addAccount);
-        addAccountButton.setOnClickListener(new View.OnClickListener() {
-            public void onClick(final View v) {
-                startChooseAccountTypeActivity();
-            }
-        });
-
         if (mPendingRequest == REQUEST_NULL) {
-            // If there are no allowable accounts go directly to add account
-            if (shouldSkipToChooseAccountTypeFlow()) {
-                startChooseAccountTypeActivity();
+            // If there are no relevant accounts and only one relevant account typoe go directly to
+            // add account. Otherwise let the user choose.
+            if (mAccountInfos.isEmpty()) {
+                if (setOfRelevantAccountTypes.size() == 1) {
+                    runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
+                } else {
+                    startChooseAccountTypeActivity();
+                }
                 return;
             }
 
@@ -229,6 +227,30 @@
                 return;
             }
         }
+
+        setContentView(R.layout.choose_type_and_account);
+
+        // there is more than one allowable account. initialize the list adapter to allow
+        // the user to select an account.
+        ListView list = (ListView) findViewById(android.R.id.list);
+        list.setAdapter(new AccountArrayAdapter(this,
+                android.R.layout.simple_list_item_1, mAccountInfos));
+        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                onListItemClick((ListView)parent, v, position, id);
+            }
+        });
+
+        // set the listener for the addAccount button
+        Button addAccountButton = (Button) findViewById(R.id.addAccount);
+        addAccountButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(final View v) {
+                startChooseAccountTypeActivity();
+            }
+        });
     }
 
     @Override
@@ -267,7 +289,7 @@
         if (resultCode == RESULT_CANCELED) {
             // if cancelling out of addAccount and the original state caused us to skip this,
             // finish this activity
-            if (shouldSkipToChooseAccountTypeFlow()) {
+            if (mAccountInfos.isEmpty()) {
                 setResult(Activity.RESULT_CANCELED);
                 finish();
             }
@@ -324,14 +346,6 @@
         finish();
     }
 
-    /**
-     * convenience method to check if we should skip the accounts list display and immediately
-     * jump to the flow that asks the user to select from the account type list
-     */
-    private boolean shouldSkipToChooseAccountTypeFlow() {
-        return mAccountInfos.isEmpty();
-    }
-
     protected void runAddAccountForAuthenticator(String type) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "runAddAccountForAuthenticator: " + type);
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index c643137..bdcb2af 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -1208,6 +1208,9 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void addChild(ViewGroup parent, View child, boolean changesLayout) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
             // Want disappearing animations to finish up before proceeding
             cancel(DISAPPEARING);
@@ -1243,6 +1246,9 @@
      * @hide
      */
     public void layoutChange(ViewGroup parent) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING  && !isRunning()) {
             // This method is called for all calls to layout() in the container, including
             // those caused by add/remove/hide/show events, which will already have set up
@@ -1301,6 +1307,9 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
             // Want appearing animations to finish up before proceeding
             cancel(APPEARING);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 69ee434..f20fd33 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3273,7 +3273,7 @@
         if (mMenuInflater == null) {
             initActionBar();
             if (mActionBar != null) {
-                mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
+                mMenuInflater = new MenuInflater(mActionBar.getThemedContext(), this);
             } else {
                 mMenuInflater = new MenuInflater(this);
             }
@@ -4999,7 +4999,8 @@
         mCurrentConfig = config;
     }
 
-    final IBinder getActivityToken() {
+    /** @hide */
+    public final IBinder getActivityToken() {
         return mParent != null ? mParent.getActivityToken() : mToken;
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4e61c3c..17b1962 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -26,7 +26,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
-import android.content.res.Configuration;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
@@ -36,16 +36,17 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserId;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -1798,6 +1799,40 @@
         }
     }
 
+    /** @hide */
+    public static int checkComponentPermission(String permission, int uid,
+            int owningUid, boolean exported) {
+        // Root, system server get to do everything.
+        if (uid == 0 || uid == Process.SYSTEM_UID) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+        // Isolated processes don't get any permissions.
+        if (UserId.isIsolated(uid)) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+        // If there is a uid that owns whatever is being accessed, it has
+        // blanket access to it regardless of the permissions it requires.
+        if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+        // If the target is not exported, then nobody else can get to it.
+        if (!exported) {
+            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
+            return PackageManager.PERMISSION_DENIED;
+        }
+        if (permission == null) {
+            return PackageManager.PERMISSION_GRANTED;
+        }
+        try {
+            return AppGlobals.getPackageManager()
+                    .checkUidPermission(permission, uid);
+        } catch (RemoteException e) {
+            // Should never happen, but if it does... deny!
+            Slog.e(TAG, "PackageManager is dead?!?", e);
+        }
+        return PackageManager.PERMISSION_DENIED;
+    }
+
     /**
      * Returns the usage statistics of each installed package.
      *
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2f2918d..4506546 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1656,6 +1656,15 @@
             return true;
         }
 
+        case GET_LAUNCHED_FROM_UID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            int res = getLaunchedFromUid(token);
+            reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3785,5 +3794,18 @@
         return result;
     }
 
+    public int getLaunchedFromUid(IBinder activityToken) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(activityToken);
+        mRemote.transact(GET_LAUNCHED_FROM_UID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return result;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b29035d..33e639e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3751,9 +3751,6 @@
         if (start) {
             try {
                 switch (profileType) {
-                    case 1:
-                        ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor());
-                        break;
                     default:                        
                         mProfiler.setProfiler(pcd.path, pcd.fd);
                         mProfiler.autoStopProfiler = false;
@@ -3772,9 +3769,6 @@
             }
         } else {
             switch (profileType) {
-                case 1:
-                    ViewDebug.stopLooperProfiling();
-                    break;
                 default:
                     mProfiler.stopProfiling();
                     break;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a2c7fa4..cf304df 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -350,6 +350,10 @@
     public boolean navigateUpTo(IBinder token, Intent target, int resultCode, Intent resultData)
             throws RemoteException;
 
+    // This is not public because you need to be very careful in how you
+    // manage your activity to make sure it is always the uid you expect.
+    public int getLaunchedFromUid(IBinder activityToken) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -592,4 +596,5 @@
     int NAVIGATE_UP_TO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+146;
     int SET_LOCK_SCREEN_SHOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+147;
     int FINISH_ACTIVITY_AFFINITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+148;
+    int GET_LAUNCHED_FROM_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+149;
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 0fe7b5c..a79a8fc 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -28,7 +28,7 @@
  * Class that can be used to lock and unlock the keyboard. Get an instance of this 
  * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
  * with argument {@link android.content.Context#KEYGUARD_SERVICE}. The
- * Actual class to control the keyboard locking is
+ * actual class to control the keyboard locking is
  * {@link android.app.KeyguardManager.KeyguardLock}.
  */
 public class KeyguardManager {
@@ -73,7 +73,7 @@
 
         /**
          * Reenable the keyguard.  The keyguard will reappear if the previous
-         * call to {@link #disableKeyguard()} caused it it to be hidden.
+         * call to {@link #disableKeyguard()} caused it to be hidden.
          *
          * A good place to call this is from {@link android.app.Activity#onPause()}
          *
@@ -130,13 +130,9 @@
     }
 
     /**
-     * isKeyguardLocked
-     *
      * Return whether the keyguard is currently locked.
      *
-     * @return true if in keyguard is locked.
-     *
-     * @hide
+     * @return true if keyguard is locked.
      */
     public boolean isKeyguardLocked() {
         try {
@@ -147,13 +143,9 @@
     }
 
     /**
-     * isKeyguardSecure
-     *
      * Return whether the keyguard requires a password to unlock.
      *
-     * @return true if in keyguard is secure.
-     *
-     * @hide
+     * @return true if keyguard is secure.
      */
     public boolean isKeyguardSecure() {
         try {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6d3aa98..3ced82b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -31,6 +32,8 @@
 import android.text.TextUtils;
 import android.util.IntProperty;
 import android.util.Log;
+import android.util.Slog;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
@@ -1378,8 +1381,8 @@
 
         private RemoteViews applyStandardTemplate(int resId) {
             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
-            boolean hasLine3 = false;
-            boolean hasLine2 = false;
+            boolean showLine3 = false;
+            boolean showLine2 = false;
             int smallIconImageViewId = R.id.icon;
             if (mLargeIcon != null) {
                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
@@ -1401,15 +1404,13 @@
                 contentView.setTextViewText(R.id.title, mContentTitle);
             }
             if (mContentText != null) {
-                contentView.setTextViewText(
-                        (mSubText != null) ? R.id.text2 : R.id.text, 
-                        mContentText);
-                hasLine3 = true;
+                contentView.setTextViewText(R.id.text, mContentText);
+                showLine3 = true;
             }
             if (mContentInfo != null) {
                 contentView.setTextViewText(R.id.info, mContentInfo);
                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
-                hasLine3 = true;
+                showLine3 = true;
             } else if (mNumber > 0) {
                 final int tooBig = mContext.getResources().getInteger(
                         R.integer.status_bar_notification_info_maxnum);
@@ -1421,25 +1422,42 @@
                     contentView.setTextViewText(R.id.info, f.format(mNumber));
                 }
                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
-                hasLine3 = true;
+                showLine3 = true;
             } else {
                 contentView.setViewVisibility(R.id.info, View.GONE);
             }
 
+            // Need to show three lines?
             if (mSubText != null) {
                 contentView.setTextViewText(R.id.text, mSubText);
-                contentView.setViewVisibility(R.id.text2,
-                        mContentText != null ? View.VISIBLE : View.GONE);
+                if (mContentText != null) {
+                    contentView.setTextViewText(R.id.text2, mContentText);
+                    // need to shrink all the type to make sure everything fits
+                    contentView.setViewVisibility(R.id.text2, View.VISIBLE);
+                    showLine2 = true;
+                } else {
+                    contentView.setViewVisibility(R.id.text2, View.GONE);
+                }
             } else {
                 contentView.setViewVisibility(R.id.text2, View.GONE);
                 if (mProgressMax != 0 || mProgressIndeterminate) {
                     contentView.setProgressBar(
                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
+                    showLine2 = true;
                 } else {
                     contentView.setViewVisibility(R.id.progress, View.GONE);
                 }
             }
+            if (showLine2) {
+                final Resources res = mContext.getResources();
+                final float subTextSize = res.getDimensionPixelSize(
+                        R.dimen.notification_subtext_size);
+                contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
+                // vertical centering
+                contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
+            }
+
             if (mWhen != 0) {
                 if (mUseChronometer) {
                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
@@ -1451,7 +1469,7 @@
                     contentView.setLong(R.id.time, "setTime", mWhen);
                 }
             }
-            contentView.setViewVisibility(R.id.line3, hasLine3 ? View.VISIBLE : View.GONE);
+            contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
             return contentView;
         }
 
@@ -1629,23 +1647,21 @@
                 mBuilder.setContentTitle(mBigContentTitle);
             }
 
-            if (mBuilder.mSubText == null) {
-                mBuilder.setContentText(null);
-            }
-
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
 
-            if (mBuilder.mSubText == null) {
-                contentView.setViewVisibility(R.id.line3, View.GONE);
-            }
-
             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
                 contentView.setViewVisibility(R.id.line1, View.GONE);
+            } else {
+                contentView.setViewVisibility(R.id.line1, View.VISIBLE);
             }
 
             if (mSummaryText != null && !mSummaryText.equals("")) {
                 contentView.setViewVisibility(R.id.overflow_title, View.VISIBLE);
                 contentView.setTextViewText(R.id.overflow_title, mSummaryText);
+                contentView.setViewVisibility(R.id.line3, View.GONE);
+            } else {
+                contentView.setViewVisibility(R.id.overflow_title, View.GONE);
+                contentView.setViewVisibility(R.id.line3, View.VISIBLE);
             }
 
             return contentView;
@@ -1673,6 +1689,8 @@
      */
     public static class BigPictureStyle extends Style {
         private Bitmap mPicture;
+        private Bitmap mBigLargeIcon;
+        private boolean mBigLargeIconSet = false;
 
         public BigPictureStyle() {
         }
@@ -1703,6 +1721,16 @@
             return this;
         }
 
+        /**
+         * @hide
+         * Override the large icon when the big notification is shown.
+         */
+        public BigPictureStyle bigLargeIcon(Bitmap b) {
+            mBigLargeIconSet = true;
+            mBigLargeIcon = b;
+            return this;
+        }
+
         private RemoteViews makeBigContentView() {
             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
 
@@ -1715,6 +1743,9 @@
         public Notification build() {
             checkBuilder();
             Notification wip = mBuilder.buildUnstyled();
+            if (mBigLargeIconSet ) {
+                mBuilder.mLargeIcon = mBigLargeIcon;
+            }
             wip.bigContentView = makeBigContentView();
             return wip;
         }
@@ -1844,7 +1875,12 @@
             contentView.setViewVisibility(R.id.text2, View.GONE);
 
             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
-                    R.id.inbox_text4};
+                    R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
+
+            // Make sure all rows are gone in case we reuse a view.
+            for (int rowId : rowIds) {
+                contentView.setViewVisibility(rowId, View.GONE);
+            }
 
             int i=0;
             while (i < mTexts.size() && i < rowIds.length) {
@@ -1856,6 +1892,12 @@
                 i++;
             }
 
+            if  (mTexts.size() > rowIds.length) {
+                contentView.setViewVisibility(R.id.inbox_more, View.VISIBLE);
+            } else {
+                contentView.setViewVisibility(R.id.inbox_more, View.GONE);
+            }
+
             return contentView;
         }
 
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index 14c5736..f21b3fd 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -161,18 +161,12 @@
             ActivityInfo info = pm.getActivityInfo(
                     new ComponentName(mSourceContext, sourceActivityClass), 0);
             String parentActivity = info.parentActivityName;
-            Intent parent = new Intent().setComponent(
-                    new ComponentName(mSourceContext, parentActivity));
-            while (parent != null) {
+            while (parentActivity != null) {
+                Intent parent = new Intent().setComponent(
+                        new ComponentName(mSourceContext, parentActivity));
                 mIntents.add(insertAt, parent);
                 info = pm.getActivityInfo(parent.getComponent(), 0);
                 parentActivity = info.parentActivityName;
-                if (parentActivity != null) {
-                    parent = new Intent().setComponent(
-                            new ComponentName(mSourceContext, parentActivity));
-                } else {
-                    parent = null;
-                }
             }
         } catch (NameNotFoundException e) {
             Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 7a8c1fb..3aa5181 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -320,6 +320,10 @@
      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
      * and outside of the handler.
      * This method will only work when called from the uid that owns the AppWidget provider.
+     * 
+     * <p>
+     * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
+     * fill the screen once, ie. (screen width x screen height x 4) bytes.
      *
      * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
      * @param views         The RemoteViews object to show.
@@ -385,6 +389,10 @@
      * and outside of the handler.
      * This method will only work when called from the uid that owns the AppWidget provider.
      *
+     * <p>
+     * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
+     * fill the screen once, ie. (screen width x screen height x 4) bytes.
+     *
      * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
      * @param views         The RemoteViews object to show.
      */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 718a917..edd509b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6653,17 +6653,20 @@
 
         final String action = getAction();
         if (ACTION_CHOOSER.equals(action)) {
-            // Inspect target intent to see if we need to migrate
-            final Intent target = getParcelableExtra(EXTRA_INTENT);
-            if (target.migrateExtraStreamToClipData()) {
-                // Since we migrated in child, we need to promote ClipData and
-                // flags to ourselves to grant.
-                setClipData(target.getClipData());
-                addFlags(target.getFlags()
-                        & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION));
-                return true;
-            } else {
-                return false;
+            try {
+                // Inspect target intent to see if we need to migrate
+                final Intent target = getParcelableExtra(EXTRA_INTENT);
+                if (target != null && target.migrateExtraStreamToClipData()) {
+                    // Since we migrated in child, we need to promote ClipData
+                    // and flags to ourselves to grant.
+                    setClipData(target.getClipData());
+                    addFlags(target.getFlags()
+                            & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION));
+                    return true;
+                } else {
+                    return false;
+                }
+            } catch (ClassCastException e) {
             }
 
         } else if (ACTION_SEND.equals(action)) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2baad62..bcdd012 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1050,6 +1050,17 @@
     public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: This is a device dedicated to showing UI
+     * on a television.  Television here is defined to be a typical living
+     * room television experience: displayed on a big screen, where the user
+     * is sitting far away from it, and the dominant form of input will be
+     * something like a DPAD, not through touch or mouse.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEVISION = "android.hardware.type.television";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 079f739..423b9af 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -42,17 +42,23 @@
     public float fontScale;
 
     /**
-     * IMSI MCC (Mobile Country Code).  0 if undefined.
+     * IMSI MCC (Mobile Country Code), corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
+     * resource qualifier.  0 if undefined.
      */
     public int mcc;
     
     /**
-     * IMSI MNC (Mobile Network Code).  0 if undefined.
+     * IMSI MNC (Mobile Network Code), corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
+     * resource qualifier.  0 if undefined.
      */
     public int mnc;
     
     /**
-     * Current user preference for the locale.
+     * Current user preference for the locale, corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
+     * resource qualifier.
      */
     public Locale locale;
 
@@ -69,29 +75,52 @@
      * value indicating that no size has been set. */
     public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
-     * value indicating the screen is at least approximately 320x426 dp units.
+     * value indicating the screen is at least approximately 320x426 dp units,
+     * corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
+     * resource qualifier.
      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
      * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
-     * value indicating the screen is at least approximately 320x470 dp units.
+     * value indicating the screen is at least approximately 320x470 dp units,
+     * corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
+     * resource qualifier.
      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
      * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
-     * value indicating the screen is at least approximately 480x640 dp units.
+     * value indicating the screen is at least approximately 480x640 dp units,
+     * corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
+     * resource qualifier.
      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
      * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
-     * value indicating the screen is at least approximately 720x960 dp units.
+     * value indicating the screen is at least approximately 720x960 dp units,
+     * corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
+     * resource qualifier.
      * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
      * Multiple Screens</a> for more information.*/
     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
-    
+
+    /** Constant for {@link #screenLayout}: bits that encode the aspect ratio. */
     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
+     * value indicating that no size has been set. */
     public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
+     * resource qualifier. */
     public static final int SCREENLAYOUT_LONG_NO = 0x10;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LONG_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
+     * resource qualifier. */
     public static final int SCREENLAYOUT_LONG_YES = 0x20;
     
     /**
@@ -135,21 +164,38 @@
         return cur >= size;
     }
 
+    /** Constant for {@link #touchscreen}: a value indicating that no value has been set. */
     public static final int TOUCHSCREEN_UNDEFINED = 0;
+    /** Constant for {@link #touchscreen}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
+     * resource qualifier. */
     public static final int TOUCHSCREEN_NOTOUCH = 1;
-    public static final int TOUCHSCREEN_STYLUS = 2;
+    /** @deprecated Not currently supported or used. */
+    @Deprecated public static final int TOUCHSCREEN_STYLUS = 2;
+    /** Constant for {@link #touchscreen}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
+     * resource qualifier. */
     public static final int TOUCHSCREEN_FINGER = 3;
     
     /**
      * The kind of touch screen attached to the device.
-     * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_STYLUS}, 
-     * {@link #TOUCHSCREEN_FINGER}. 
+     * One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}.
      */
     public int touchscreen;
-    
+
+    /** Constant for {@link #keyboard}: a value indicating that no value has been set. */
     public static final int KEYBOARD_UNDEFINED = 0;
+    /** Constant for {@link #keyboard}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
+     * resource qualifier. */
     public static final int KEYBOARD_NOKEYS = 1;
+    /** Constant for {@link #keyboard}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
+     * resource qualifier. */
     public static final int KEYBOARD_QWERTY = 2;
+    /** Constant for {@link #keyboard}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
+     * resource qualifier. */
     public static final int KEYBOARD_12KEY = 3;
     
     /**
@@ -158,9 +204,16 @@
      * {@link #KEYBOARD_12KEY}.
      */
     public int keyboard;
-    
+
+    /** Constant for {@link #keyboardHidden}: a value indicating that no value has been set. */
     public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
+    /** Constant for {@link #keyboardHidden}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
+     * resource qualifier. */
     public static final int KEYBOARDHIDDEN_NO = 1;
+    /** Constant for {@link #keyboardHidden}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
+     * resource qualifier. */
     public static final int KEYBOARDHIDDEN_YES = 2;
     /** Constant matching actual resource implementation. {@hide} */
     public static final int KEYBOARDHIDDEN_SOFT = 3;
@@ -174,8 +227,13 @@
      */
     public int keyboardHidden;
     
+    /** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */
     public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
+    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
+     * physical keyboard being exposed. */
     public static final int HARDKEYBOARDHIDDEN_NO = 1;
+    /** Constant for {@link #hardKeyboardHidden}, value corresponding to the
+     * physical keyboard being hidden. */
     public static final int HARDKEYBOARDHIDDEN_YES = 2;
     
     /**
@@ -186,10 +244,23 @@
      */
     public int hardKeyboardHidden;
     
+    /** Constant for {@link #navigation}: a value indicating that no value has been set. */
     public static final int NAVIGATION_UNDEFINED = 0;
+    /** Constant for {@link #navigation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
+     * resource qualifier. */
     public static final int NAVIGATION_NONAV = 1;
+    /** Constant for {@link #navigation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
+     * resource qualifier. */
     public static final int NAVIGATION_DPAD = 2;
+    /** Constant for {@link #navigation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
+     * resource qualifier. */
     public static final int NAVIGATION_TRACKBALL = 3;
+    /** Constant for {@link #navigation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
+     * resource qualifier. */
     public static final int NAVIGATION_WHEEL = 4;
     
     /**
@@ -199,8 +270,15 @@
      */
     public int navigation;
     
+    /** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */
     public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
+    /** Constant for {@link #navigationHidden}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
+     * resource qualifier. */
     public static final int NAVIGATIONHIDDEN_NO = 1;
+    /** Constant for {@link #navigationHidden}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
+     * resource qualifier. */
     public static final int NAVIGATIONHIDDEN_YES = 2;
     
     /**
@@ -211,29 +289,70 @@
      */
     public int navigationHidden;
     
+    /** Constant for {@link #orientation}: a value indicating that no value has been set. */
     public static final int ORIENTATION_UNDEFINED = 0;
+    /** Constant for {@link #orientation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
+     * resource qualifier. */
     public static final int ORIENTATION_PORTRAIT = 1;
+    /** Constant for {@link #orientation}, value corresponding to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
+     * resource qualifier. */
     public static final int ORIENTATION_LANDSCAPE = 2;
-    public static final int ORIENTATION_SQUARE = 3;
+    /** @deprecated Not currently supported or used. */
+    @Deprecated public static final int ORIENTATION_SQUARE = 3;
     
     /**
      * Overall orientation of the screen.  May be one of
-     * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
-     * or {@link #ORIENTATION_SQUARE}.
+     * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
      */
     public int orientation;
 
+    /** Constant for {@link #uiMode}: bits that encode the mode type. */
     public static final int UI_MODE_TYPE_MASK = 0x0f;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value indicating that no mode type has been set. */
     public static final int UI_MODE_TYPE_UNDEFINED = 0x00;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">no
+     * UI mode</a> resource qualifier specified. */
     public static final int UI_MODE_TYPE_NORMAL = 0x01;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a>
+     * resource qualifier. */
     public static final int UI_MODE_TYPE_DESK = 0x02;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">car</a>
+     * resource qualifier. */
     public static final int UI_MODE_TYPE_CAR = 0x03;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">television</a>
+     * resource qualifier. */
     public static final int UI_MODE_TYPE_TELEVISION = 0x04;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
+     * resource qualifier. */
     public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
 
+    /** Constant for {@link #uiMode}: bits that encode the night mode. */
     public static final int UI_MODE_NIGHT_MASK = 0x30;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
+     * value indicating that no mode type has been set. */
     public static final int UI_MODE_NIGHT_UNDEFINED = 0x00;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">notnight</a>
+     * resource qualifier. */
     public static final int UI_MODE_NIGHT_NO = 0x10;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_NIGHT_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#NightQualifier">night</a>
+     * resource qualifier. */
     public static final int UI_MODE_NIGHT_YES = 0x20;
 
     /**
@@ -253,21 +372,30 @@
     public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
 
     /**
-     * The current width of the available screen space, in dp units.
+     * The current width of the available screen space, in dp units,
+     * corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenWidthQualifier">screen
+     * width</a> resource qualifier.
      */
     public int screenWidthDp;
 
     public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
 
     /**
-     * The current height of the available screen space, in dp units.
+     * The current height of the available screen space, in dp units,
+     * corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenHeightQualifier">screen
+     * height</a> resource qualifier.
      */
     public int screenHeightDp;
 
     public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0;
 
     /**
-     * The smallest screen size an application will see in normal operation.
+     * The smallest screen size an application will see in normal operation,
+     * corresponding to
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest
+     * screen width</a> resource qualifier.
      * This is the smallest value of both screenWidthDp and screenHeightDp
      * in both portrait and landscape.
      */
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c682852..c630bb5 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -630,7 +630,20 @@
      * Various types of objects will be returned depending on the underlying
      * resource -- for example, a solid color, PNG image, scalable image, etc.
      * The Drawable API hides these implementation details.
-     * 
+     *
+     * <p class="note"><strong>Note:</strong> Prior to
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function
+     * would not correctly retrieve the final configuration density when
+     * the resource ID passed here is an alias to another Drawable resource.
+     * This means that if the density configuration of the alias resource
+     * is different than the actual resource, the density of the returned
+     * Drawable would be incorrect, resulting in bad scaling.  To work
+     * around this, you can instead retrieve the Drawable through
+     * {@link TypedArray#getDrawable TypedArray.getDrawable}.  Use
+     * {@link android.content.Context#obtainStyledAttributes(int[])
+     * Context.obtainStyledAttributes} with
+     * an array containing the resource ID of interest to create the TypedArray.</p>
+     *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index aeb46cf..b8ad818 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1122,9 +1122,9 @@
 
     /** Helper function to compute the angle change between two rotation matrices.
      *  Given a current rotation matrix (R) and a previous rotation matrix
-     *  (prevR) computes the rotation around the x,y, and z axes which
+     *  (prevR) computes the rotation around the z,x, and y axes which
      *  transforms prevR to R.
-     *  outputs a 3 element vector containing the x,y, and z angle
+     *  outputs a 3 element vector containing the z,x, and y angle
      *  change at indexes 0, 1, and 2 respectively.
      * <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix
      * depending on the length of the passed array:
@@ -1143,14 +1143,13 @@
      *</pre>
      * @param R current rotation matrix
      * @param prevR previous rotation matrix
-     * @param angleChange an array of floats in which the angle change is stored
+     * @param angleChange an an array of floats (z, x, and y) in which the angle change is stored
      */
 
     public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) {
         float rd1=0,rd4=0, rd6=0,rd7=0, rd8=0;
         float ri0=0,ri1=0,ri2=0,ri3=0,ri4=0,ri5=0,ri6=0,ri7=0,ri8=0;
         float pri0=0, pri1=0, pri2=0, pri3=0, pri4=0, pri5=0, pri6=0, pri7=0, pri8=0;
-        int i, j, k;
 
         if(R.length == 9) {
             ri0 = R[0];
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 3137947..9b6f82a 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -41,8 +41,13 @@
     // Keyboard layouts configuration.
     KeyboardLayout[] getKeyboardLayouts();
     KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
-    String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor);
-    void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor);
+    void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor);
+    String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor);
+    void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor);
+    void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
             String keyboardLayoutDescriptor);
 
     // Registers an input devices changed listener.
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6448b55..262d87d 100755
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,6 +16,8 @@
 
 package android.hardware.input;
 
+import com.android.internal.util.ArrayUtils;
+
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
@@ -77,7 +79,8 @@
      * The meta-data specifies a resource that contains a description of each keyboard
      * layout that is provided by the application.
      * <pre><code>
-     * &lt;receiver android:name=".InputDeviceReceiver">
+     * &lt;receiver android:name=".InputDeviceReceiver"
+     *         android:label="@string/keyboard_layouts_label">
      *     &lt;intent-filter>
      *         &lt;action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
      *     &lt;/intent-filter>
@@ -90,7 +93,9 @@
      * an XML resource whose root element is <code>&lt;keyboard-layouts></code> that
      * contains zero or more <code>&lt;keyboard-layout></code> elements.
      * Each <code>&lt;keyboard-layout></code> element specifies the name, label, and location
-     * of a key character map for a particular keyboard layout.
+     * of a key character map for a particular keyboard layout.  The label on the receiver
+     * is used to name the collection of keyboard layouts provided by this receiver in the
+     * keyboard layout settings.
      * <pre></code>
      * &lt;?xml version="1.0" encoding="utf-8"?>
      * &lt;keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
@@ -214,6 +219,41 @@
     }
 
     /**
+     * Gets information about the input device with the specified descriptor.
+     * @param descriptor The input device descriptor.
+     * @return The input device or null if not found.
+     * @hide
+     */
+    public InputDevice getInputDeviceByDescriptor(String descriptor) {
+        if (descriptor == null) {
+            throw new IllegalArgumentException("descriptor must not be null.");
+        }
+
+        synchronized (mInputDevicesLock) {
+            populateInputDevicesLocked();
+
+            int numDevices = mInputDevices.size();
+            for (int i = 0; i < numDevices; i++) {
+                InputDevice inputDevice = mInputDevices.valueAt(i);
+                if (inputDevice == null) {
+                    int id = mInputDevices.keyAt(i);
+                    try {
+                        inputDevice = mIm.getInputDevice(id);
+                    } catch (RemoteException ex) {
+                        // Ignore the problem for the purposes of this method.
+                        continue;
+                    }
+                    mInputDevices.setValueAt(i, inputDevice);
+                }
+                if (descriptor.equals(inputDevice.getDescriptor())) {
+                    return inputDevice;
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
      * Gets the ids of all input devices in the system.
      * @return The input device ids.
      */
@@ -329,50 +369,129 @@
     }
 
     /**
-     * Gets the keyboard layout descriptor for the specified input device.
+     * Gets the current keyboard layout descriptor for the specified input device.
      *
      * @param inputDeviceDescriptor The input device descriptor.
-     * @return The keyboard layout descriptor, or null if unknown or if the default
-     * keyboard layout will be used.
+     * @return The keyboard layout descriptor, or null if no keyboard layout has been set.
      *
      * @hide
      */
-    public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
+    public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
         if (inputDeviceDescriptor == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
         try {
-            return mIm.getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+            return mIm.getCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get keyboard layout for input device.", ex);
+            Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
             return null;
         }
     }
 
     /**
-     * Sets the keyboard layout descriptor for the specified input device.
+     * Sets the current keyboard layout descriptor for the specified input device.
      * <p>
      * This method may have the side-effect of causing the input device in question
      * to be reconfigured.
      * </p>
      *
      * @param inputDeviceDescriptor The input device descriptor.
-     * @param keyboardLayoutDescriptor The keyboard layout descriptor, or null to remove
-     * the mapping so that the default keyboard layout will be used for the input device.
+     * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, must not be null.
      *
      * @hide
      */
-    public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
             String keyboardLayoutDescriptor) {
         if (inputDeviceDescriptor == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        try {
+            mIm.setCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor,
+                    keyboardLayoutDescriptor);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
+        }
+    }
+
+    /**
+     * Gets all keyboard layout descriptors that are enabled for the specified input device.
+     *
+     * @param inputDeviceDescriptor The input device descriptor.
+     * @return The keyboard layout descriptors.
+     *
+     * @hide
+     */
+    public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
 
         try {
-            mIm.setKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+            return mIm.getKeyboardLayoutsForInputDevice(inputDeviceDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set keyboard layout for input device.", ex);
+            Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
+            return ArrayUtils.emptyArray(String.class);
+        }
+    }
+
+    /**
+     * Adds the keyboard layout descriptor for the specified input device.
+     * <p>
+     * This method may have the side-effect of causing the input device in question
+     * to be reconfigured.
+     * </p>
+     *
+     * @param inputDeviceDescriptor The input device descriptor.
+     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to add.
+     *
+     * @hide
+     */
+    public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        try {
+            mIm.addKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not add keyboard layout for input device.", ex);
+        }
+    }
+
+    /**
+     * Removes the keyboard layout descriptor for the specified input device.
+     * <p>
+     * This method may have the side-effect of causing the input device in question
+     * to be reconfigured.
+     * </p>
+     *
+     * @param inputDeviceDescriptor The input device descriptor.
+     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to remove.
+     *
+     * @hide
+     */
+    public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        try {
+            mIm.removeKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
         }
     }
 
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index e75a6dc..5402e75 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -28,6 +28,7 @@
         Comparable<KeyboardLayout> {
     private final String mDescriptor;
     private final String mLabel;
+    private final String mCollection;
 
     public static final Parcelable.Creator<KeyboardLayout> CREATOR =
             new Parcelable.Creator<KeyboardLayout>() {
@@ -39,14 +40,16 @@
         }
     };
 
-    public KeyboardLayout(String descriptor, String label) {
+    public KeyboardLayout(String descriptor, String label, String collection) {
         mDescriptor = descriptor;
         mLabel = label;
+        mCollection = collection;
     }
 
     private KeyboardLayout(Parcel source) {
         mDescriptor = source.readString();
         mLabel = source.readString();
+        mCollection = source.readString();
     }
 
     /**
@@ -68,6 +71,15 @@
         return mLabel;
     }
 
+    /**
+     * Gets the name of the collection to which the keyboard layout belongs.  This is
+     * the label of the broadcast receiver or application that provided the keyboard layout.
+     * @return The keyboard layout collection name.
+     */
+    public String getCollection() {
+        return mCollection;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -77,15 +89,23 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mDescriptor);
         dest.writeString(mLabel);
+        dest.writeString(mCollection);
     }
 
     @Override
     public int compareTo(KeyboardLayout another) {
-        return mLabel.compareToIgnoreCase(another.mLabel);
+        int result = mLabel.compareToIgnoreCase(another.mLabel);
+        if (result == 0) {
+            result = mCollection.compareToIgnoreCase(another.mCollection);
+        }
+        return result;
     }
 
     @Override
     public String toString() {
-        return mLabel;
+        if (mCollection.isEmpty()) {
+            return mLabel;
+        }
+        return mLabel + " - " + mCollection;
     }
 }
\ No newline at end of file
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 7257521..4916244 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -855,15 +855,23 @@
                 Key oldKey = keys[oldKeyIndex];
                 oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY);
                 invalidateKey(oldKeyIndex);
+                final int keyCode = oldKey.codes[0];
                 sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT,
-                        oldKey.codes[0]);
+                        keyCode);
+                // TODO: We need to implement AccessibilityNodeProvider for this view.
+                sendAccessibilityEventForUnicodeCharacter(
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, keyCode);
             }
             if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
                 Key newKey = keys[mCurrentKeyIndex];
                 newKey.onPressed();
                 invalidateKey(mCurrentKeyIndex);
+                final int keyCode = newKey.codes[0];
                 sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                        newKey.codes[0]);
+                        keyCode);
+                // TODO: We need to implement AccessibilityNodeProvider for this view.
+                sendAccessibilityEventForUnicodeCharacter(
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, keyCode);
             }
         }
         // If key changed and preview is on ...
@@ -1154,20 +1162,17 @@
         if (mAccessibilityManager.isTouchExplorationEnabled() && event.getPointerCount() == 1) {
             final int action = event.getAction();
             switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                case MotionEvent.ACTION_HOVER_MOVE:
-                    final int touchX = (int) event.getX() - mPaddingLeft;
-                    int touchY = (int) event.getY() - mPaddingTop;
-                    if (touchY >= -mVerticalCorrection) {
-                        touchY += mVerticalCorrection;
-                    }
-                    final int keyIndex = getKeyIndices(touchX, touchY, null);
-                    showPreview(keyIndex);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    showPreview(NOT_A_KEY);
-                    break;
+                case MotionEvent.ACTION_HOVER_ENTER: {
+                    event.setAction(MotionEvent.ACTION_DOWN);
+                } break;
+                case MotionEvent.ACTION_HOVER_MOVE: {
+                    event.setAction(MotionEvent.ACTION_MOVE);
+                } break;
+                case MotionEvent.ACTION_HOVER_EXIT: {
+                    event.setAction(MotionEvent.ACTION_UP);
+                } break;
             }
+            return onTouchEvent(event);
         }
         return true;
     }
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 844d055..fb7a4f8 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -111,6 +111,14 @@
                     && operations == 0;
         }
 
+        public void add(Entry another) {
+            this.rxBytes += another.rxBytes;
+            this.rxPackets += another.rxPackets;
+            this.txBytes += another.txBytes;
+            this.txPackets += another.txPackets;
+            this.operations += another.operations;
+        }
+
         @Override
         public String toString() {
             final StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 0003c6e..a37c26f9 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -342,11 +342,23 @@
      * for combining together stats for external reporting.
      */
     public void recordEntireHistory(NetworkStatsHistory input) {
+        recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
+    }
+
+    /**
+     * Record given {@link NetworkStatsHistory} into this history, copying only
+     * buckets that atomically occur in the inclusive time range. Doesn't
+     * interpolate across partial buckets.
+     */
+    public void recordHistory(NetworkStatsHistory input, long start, long end) {
         final NetworkStats.Entry entry = new NetworkStats.Entry(
                 IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
         for (int i = 0; i < input.bucketCount; i++) {
-            final long start = input.bucketStart[i];
-            final long end = start + input.bucketDuration;
+            final long bucketStart = input.bucketStart[i];
+            final long bucketEnd = bucketStart + input.bucketDuration;
+
+            // skip when bucket is outside requested range
+            if (bucketStart < start || bucketEnd > end) continue;
 
             entry.rxBytes = getLong(input.rxBytes, i, 0L);
             entry.rxPackets = getLong(input.rxPackets, i, 0L);
@@ -354,7 +366,7 @@
             entry.txPackets = getLong(input.txPackets, i, 0L);
             entry.operations = getLong(input.operations, i, 0L);
 
-            recordData(start, end, entry);
+            recordData(bucketStart, bucketEnd, entry);
         }
     }
 
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 39a4d7b..d8e53d5 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -61,6 +61,13 @@
                 com.android.internal.R.array.config_data_usage_network_types);
     }
 
+    private static boolean sForceAllNetworkTypes = false;
+
+    // @VisibleForTesting
+    public static void forceAllNetworkTypes() {
+        sForceAllNetworkTypes = true;
+    }
+
     /**
      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
      * the given IMSI.
@@ -225,7 +232,7 @@
             // TODO: consider matching against WiMAX subscriber identity
             return true;
         } else {
-            return (contains(DATA_USAGE_NETWORK_TYPES, ident.mType)
+            return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
                     && Objects.equal(mSubscriberId, ident.mSubscriberId));
         }
     }
@@ -291,7 +298,7 @@
         if (ident.mType == TYPE_WIMAX) {
             return true;
         } else {
-            return contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
+            return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
         }
     }
 
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 6a4f1f2..2703f1d 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -261,8 +261,8 @@
      * server then the first protocol in the client's list will be selected.
      * The order of the client's protocols is otherwise insignificant.
      *
-     * @param npnProtocols a possibly-empty list of protocol byte arrays. All
-     *     arrays must be non-empty and of length less than 256.
+     * @param npnProtocols a non-empty list of protocol byte arrays. All arrays
+     *     must be non-empty and of length less than 256.
      */
     public void setNpnProtocols(byte[][] npnProtocols) {
         this.mNpnProtocols = toNpnProtocolsList(npnProtocols);
@@ -273,6 +273,9 @@
      * strings.
      */
     static byte[] toNpnProtocolsList(byte[]... npnProtocols) {
+        if (npnProtocols.length == 0) {
+            throw new IllegalArgumentException("npnProtocols.length == 0");
+        }
         int totalLength = 0;
         for (byte[] s : npnProtocols) {
             if (s.length == 0 || s.length > 255) {
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 7ffa575..53b41d5 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -299,7 +299,23 @@
             callback = state.uriCallback;
         }
         if (callback != null) {
-            return callback.createBeamUris(mDefaultEvent);
+            uris = callback.createBeamUris(mDefaultEvent);
+            if (uris != null) {
+                for (Uri uri : uris) {
+                    if (uri == null) {
+                        Log.e(TAG, "Uri not allowed to be null.");
+                        return null;
+                    }
+                    String scheme = uri.getScheme();
+                    if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+                            !scheme.equalsIgnoreCase("content"))) {
+                        Log.e(TAG, "Uri needs to have " +
+                                "either scheme file or scheme content");
+                        return null;
+                    }
+                }
+            }
+            return uris;
         } else {
             return uris;
         }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 7bf9feb..4464d58 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -584,17 +584,138 @@
         }
     }
 
-    //TODO: make sure NFC service has permission for URI
-    //TODO: see if we will eventually support multiple URIs
-    //TODO: javadoc
+    /**
+     * Set one or more {@link Uri}s to send using Android Beam (TM). Every
+     * Uri you provide must have either scheme 'file' or scheme 'content'.
+     *
+     * <p>For the data provided through this method, Android Beam tries to
+     * switch to alternate transports such as Bluetooth to achieve a fast
+     * transfer speed. Hence this method is very suitable
+     * for transferring large files such as pictures or songs.
+     *
+     * <p>The receiving side will store the content of each Uri in
+     * a file and present a notification to the user to open the file
+     * with a {@link android.content.Intent} with action
+     * {@link android.content.Intent#ACTION_VIEW}.
+     * If multiple URIs are sent, the {@link android.content.Intent} will refer
+     * to the first of the stored files.
+     *
+     * <p>This method may be called at any time before {@link Activity#onDestroy},
+     * but the URI(s) are only made available for Android Beam when the
+     * specified activity(s) are in resumed (foreground) state. The recommended
+     * approach is to call this method during your Activity's
+     * {@link Activity#onCreate} - see sample
+     * code below. This method does not immediately perform any I/O or blocking work,
+     * so is safe to call on your main thread.
+     *
+     * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
+     * have priority over both {@link #setNdefPushMessage} and
+     * {@link #setNdefPushMessageCallback}.
+     *
+     * <p>If {@link #setBeamPushUris} is called with a null Uri array,
+     * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
+     * then the Uri push will be completely disabled for the specified activity(s).
+     *
+     * <p>Code example:
+     * <pre>
+     * protected void onCreate(Bundle savedInstanceState) {
+     *     super.onCreate(savedInstanceState);
+     *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+     *     if (nfcAdapter == null) return;  // NFC not available on this device
+     *     nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
+     * }
+     * </pre>
+     * And that is it. Only one call per activity is necessary. The Android
+     * OS will automatically release its references to the Uri(s) and the
+     * Activity object when it is destroyed if you follow this pattern.
+     *
+     * <p>If your Activity wants to dynamically supply Uri(s),
+     * then set a callback using {@link #setBeamPushUrisCallback} instead
+     * of using this method.
+     *
+     * <p class="note">Do not pass in an Activity that has already been through
+     * {@link Activity#onDestroy}. This is guaranteed if you call this API
+     * during {@link Activity#onCreate}.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param uris an array of Uri(s) to push over Android Beam
+     * @param activity activity for which the Uri(s) will be pushed
+     */
     public void setBeamPushUris(Uri[] uris, Activity activity) {
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
+        if (uris != null) {
+            for (Uri uri : uris) {
+                if (uri == null) throw new NullPointerException("Uri not " +
+                        "allowed to be null");
+                String scheme = uri.getScheme();
+                if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+                        !scheme.equalsIgnoreCase("content"))) {
+                    throw new IllegalArgumentException("URI needs to have " +
+                            "either scheme file or scheme content");
+                }
+            }
+        }
         mNfcActivityManager.setNdefPushContentUri(activity, uris);
     }
 
-    // TODO javadoc
+    /**
+     * Set a callback that will dynamically generate one or more {@link Uri}s
+     * to send using Android Beam (TM). Every Uri the callback provides
+     * must have either scheme 'file' or scheme 'content'.
+     *
+     * <p>For the data provided through this callback, Android Beam tries to
+     * switch to alternate transports such as Bluetooth to achieve a fast
+     * transfer speed. Hence this method is very suitable
+     * for transferring large files such as pictures or songs.
+     *
+     * <p>The receiving side will store the content of each Uri in
+     * a file and present a notification to the user to open the file
+     * with a {@link android.content.Intent} with action
+     * {@link android.content.Intent#ACTION_VIEW}.
+     * If multiple URIs are sent, the {@link android.content.Intent} will refer
+     * to the first of the stored files.
+     *
+     * <p>This method may be called at any time before {@link Activity#onDestroy},
+     * but the URI(s) are only made available for Android Beam when the
+     * specified activity(s) are in resumed (foreground) state. The recommended
+     * approach is to call this method during your Activity's
+     * {@link Activity#onCreate} - see sample
+     * code below. This method does not immediately perform any I/O or blocking work,
+     * so is safe to call on your main thread.
+     *
+     * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
+     * have priority over both {@link #setNdefPushMessage} and
+     * {@link #setNdefPushMessageCallback}.
+     *
+     * <p>If {@link #setBeamPushUris} is called with a null Uri array,
+     * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
+     * then the Uri push will be completely disabled for the specified activity(s).
+     *
+     * <p>Code example:
+     * <pre>
+     * protected void onCreate(Bundle savedInstanceState) {
+     *     super.onCreate(savedInstanceState);
+     *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+     *     if (nfcAdapter == null) return;  // NFC not available on this device
+     *     nfcAdapter.setBeamPushUrisCallback(callback, this);
+     * }
+     * </pre>
+     * And that is it. Only one call per activity is necessary. The Android
+     * OS will automatically release its references to the Uri(s) and the
+     * Activity object when it is destroyed if you follow this pattern.
+     *
+     * <p class="note">Do not pass in an Activity that has already been through
+     * {@link Activity#onDestroy}. This is guaranteed if you call this API
+     * during {@link Activity#onCreate}.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param callback callback, or null to disable
+     * @param activity activity for which the Uri(s) will be pushed
+     */
     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
@@ -663,6 +784,10 @@
      * {@link Activity#onDestroy}. This is guaranteed if you call this API
      * during {@link Activity#onCreate}.
      *
+     * <p class="note">For sending large content such as pictures and songs,
+     * consider using {@link #setBeamPushUris}, which switches to alternate transports
+     * such as Bluetooth to achieve a fast transfer rate.
+     *
      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      *
      * @param message NDEF message to push over NFC, or null to disable
@@ -753,7 +878,9 @@
      * <p class="note">Do not pass in an Activity that has already been through
      * {@link Activity#onDestroy}. This is guaranteed if you call this API
      * during {@link Activity#onCreate}.
-     *
+     * <p class="note">For sending large content such as pictures and songs,
+     * consider using {@link #setBeamPushUris}, which switches to alternate transports
+     * such as Bluetooth to achieve a fast transfer rate.
      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      *
      * @param callback callback, or null to disable
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 97ed235..69e1de9 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -36,6 +36,13 @@
  * perform background operations and publish results on the UI thread without
  * having to manipulate threads and/or handlers.</p>
  *
+ * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
+ * and does not constitute a generic threading framework. AsyncTasks should ideally be
+ * used for short operations (a few seconds at the most.) If you need to keep threads
+ * running for long periods of time, it is highly recommended you use the various APIs
+ * provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},
+ * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
+ *
  * <p>An asynchronous task is defined by a computation that runs on a background thread and
  * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
  * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
@@ -63,6 +70,8 @@
  *         for (int i = 0; i < count; i++) {
  *             totalSize += Downloader.downloadFile(urls[i]);
  *             publishProgress((int) ((i / (float) count) * 100));
+ *             // Escape early if cancel() is called
+ *             if (isCancelled()) break;
  *         }
  *         return totalSize;
  *     }
@@ -154,6 +163,16 @@
  *     <li>Set member fields in {@link #doInBackground}, and refer to them in
  *     {@link #onProgressUpdate} and {@link #onPostExecute}.
  * </ul>
+ *
+ * <h2>Order of execution</h2>
+ * <p>When first introduced, AsyncTasks were executed serially on a single background
+ * thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
+ * to a pool of threads allowing multiple tasks to operate in parallel. Starting with
+ * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
+ * thread to avoid common application errors caused by parallel execution.</p>
+ * <p>If you truly want parallel execution, you can invoke
+ * {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
+ * {@link #THREAD_POOL_EXECUTOR}.</p>
  */
 public abstract class AsyncTask<Params, Progress, Result> {
     private static final String LOG_TAG = "AsyncTask";
@@ -491,13 +510,13 @@
      * thread or pool of threads depending on the platform version.  When first
      * introduced, AsyncTasks were executed serially on a single background thread.
      * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
-     * to a pool of threads allowing multiple tasks to operate in parallel.  After
-     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, it is planned to change this
-     * back to a single thread to avoid common application errors caused
+     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
+     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
+     * executed on a single thread to avoid common application errors caused
      * by parallel execution.  If you truly want parallel execution, you can use
      * the {@link #executeOnExecutor} version of this method
-     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings on
-     * its use.
+     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
+     * on its use.
      *
      * <p>This method must be invoked on the UI thread.
      *
@@ -507,6 +526,9 @@
      *
      * @throws IllegalStateException If {@link #getStatus()} returns either
      *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+     *
+     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
+     * @see #execute(Runnable)
      */
     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
         return executeOnExecutor(sDefaultExecutor, params);
@@ -542,6 +564,8 @@
      *
      * @throws IllegalStateException If {@link #getStatus()} returns either
      *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+     *
+     * @see #execute(Object[])
      */
     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
             Params... params) {
@@ -569,7 +593,11 @@
 
     /**
      * Convenience version of {@link #execute(Object...)} for use with
-     * a simple Runnable object.
+     * a simple Runnable object. See {@link #execute(Object[])} for more
+     * information on the order of execution.
+     *
+     * @see #execute(Object[])
+     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
      */
     public static void execute(Runnable runnable) {
         sDefaultExecutor.execute(runnable);
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f7f0263..679cf1a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -94,6 +94,16 @@
     }
 
     /**
+     * Return directory used for internal media storage, which is protected by
+     * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
+     *
+     * @hide
+     */
+    public static File getMediaStorageDirectory() {
+        return MEDIA_STORAGE_DIRECTORY;
+    }
+
+    /**
      * Returns whether the Encrypted File System feature is enabled on the device or not.
      * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
      * if disabled.
@@ -112,6 +122,10 @@
     private static final File SECURE_DATA_DIRECTORY
             = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
 
+    /** @hide */
+    private static final File MEDIA_STORAGE_DIRECTORY
+            = getDirectory("MEDIA_STORAGE", "/data/media");
+
     private static final File EXTERNAL_STORAGE_DIRECTORY
             = getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0");
 
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a06aadb6..02135bc 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -127,29 +127,17 @@
                 return;
             }
 
-            long wallStart = 0;
-            long threadStart = 0;
-
             // This must be in a local variable, in case a UI event sets the logger
             Printer logging = me.mLogging;
             if (logging != null) {
                 logging.println(">>>>> Dispatching to " + msg.target + " " +
                         msg.callback + ": " + msg.what);
-                wallStart = SystemClock.currentTimeMicro();
-                threadStart = SystemClock.currentThreadTimeMicro();
             }
 
             msg.target.dispatchMessage(msg);
 
             if (logging != null) {
-                long wallTime = SystemClock.currentTimeMicro() - wallStart;
-                long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
-
                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
-                if (logging instanceof Profiler) {
-                    ((Profiler) logging).profile(msg, wallStart, wallTime,
-                            threadStart, threadTime);
-                }
             }
 
             // Make sure that during the course of dispatching the
@@ -290,12 +278,4 @@
     public String toString() {
         return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
     }
-
-    /**
-     * @hide
-     */
-    public static interface Profiler {
-        void profile(Message message, long wallStart, long wallTime,
-                long threadStart, long threadTime);
-    }
 }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index c0240fe..d2050b7 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -43,7 +43,7 @@
     public static final int TRACE_FLAGS_START_BIT = 1;
     public static final String[] TRACE_TAGS = {
         "Graphics", "Input", "View", "WebView", "Window Manager",
-        "Activity Manager", "Sync Manager", "Audio"
+        "Activity Manager", "Sync Manager", "Audio", "Video",
     };
 
     public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index f4abda6..ab64866 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1360,7 +1360,14 @@
      */
     public Parcelable[] getVolumeList() throws RemoteException;
 
-    public String getSecureContainerFilesystemPath(String id) throws RemoteException;
+    /**
+     * Gets the path on the filesystem for the ASEC container itself.
+     * 
+     * @param cid ASEC container ID
+     * @return path to filesystem or {@code null} if it's not found
+     * @throws RemoteException
+     */
+    public String getSecureContainerFilesystemPath(String cid) throws RemoteException;
 
     /*
      * Fix permissions in a container which has just been created and populated.
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 2c4b8631..79c8f3b 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,6 +16,7 @@
 
 package android.os.storage;
 
+import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,7 +29,7 @@
     //private static final String TAG = "StorageVolume";
 
     private final String mPath;
-    private final String mDescription;
+    private final int mDescriptionId;
     private final boolean mRemovable;
     private final boolean mEmulated;
     private final int mMtpReserveSpace;
@@ -42,10 +43,10 @@
     // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
     public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
 
-    public StorageVolume(String path, String description, boolean removable,
+    public StorageVolume(String path, int descriptionId, boolean removable,
             boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize) {
         mPath = path;
-        mDescription = description;
+        mDescriptionId = descriptionId;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSpace = mtpReserveSpace;
@@ -54,11 +55,11 @@
     }
 
     // for parcelling only
-    private StorageVolume(String path, String description, boolean removable,
+    private StorageVolume(String path, int descriptionId, boolean removable,
             boolean emulated, int mtpReserveSpace, int storageId,
             boolean allowMassStorage, long maxFileSize) {
         mPath = path;
-        mDescription = description;
+        mDescriptionId = descriptionId;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSpace = mtpReserveSpace;
@@ -81,8 +82,12 @@
      *
      * @return the volume description
      */
-    public String getDescription() {
-        return mDescription;
+    public String getDescription(Context context) {
+        return context.getResources().getString(mDescriptionId);
+    }
+
+    public int getDescriptionId() {
+        return mDescriptionId;
     }
 
     /**
@@ -172,8 +177,8 @@
 
     @Override
     public String toString() {
-        return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescription="
-                + mDescription + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
+        return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescriptionId="
+                + mDescriptionId + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
                 + ", mMtpReserveSpace=" + mMtpReserveSpace + ", mPath=" + mPath + ", mRemovable="
                 + mRemovable + ", mStorageId=" + mStorageId + "]";
     }
@@ -182,14 +187,14 @@
         new Parcelable.Creator<StorageVolume>() {
         public StorageVolume createFromParcel(Parcel in) {
             String path = in.readString();
-            String description = in.readString();
+            int descriptionId = in.readInt();
             int removable = in.readInt();
             int emulated = in.readInt();
             int storageId = in.readInt();
             int mtpReserveSpace = in.readInt();
             int allowMassStorage = in.readInt();
             long maxFileSize = in.readLong();
-            return new StorageVolume(path, description,
+            return new StorageVolume(path, descriptionId,
                     removable == 1, emulated == 1, mtpReserveSpace,
                     storageId, allowMassStorage == 1, maxFileSize);
         }
@@ -205,7 +210,7 @@
 
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mPath);
-        parcel.writeString(mDescription);
+        parcel.writeInt(mDescriptionId);
         parcel.writeInt(mRemovable ? 1 : 0);
         parcel.writeInt(mEmulated ? 1 : 0);
         parcel.writeInt(mStorageId);
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index c59ed18..a643c8a 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -261,6 +261,8 @@
     
     @Override
     protected void onClick() {
+        if (mDialog != null && mDialog.isShowing()) return;
+
         showDialog(null);
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ea3cab4..8b7ee0e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4210,6 +4210,8 @@
         public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
         /** {@hide} */
         public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+        /** {@hide} */
+        public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev";
 
         /** {@hide} */
         public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
@@ -4266,6 +4268,13 @@
                 "contacts_preauth_uri_expiration";
 
         /**
+         * Prefix for SMS short code regex patterns (country code is appended).
+         * @see com.android.internal.telephony.SmsUsageMonitor
+         * @hide
+         */
+        public static final String SMS_SHORT_CODES_PREFIX = "sms_short_codes_";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 3cf207f..97c0209 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -530,7 +530,7 @@
         // Bluetooth stack needs a small delay here before adding
         // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
         try {
-            Thread.sleep(20);
+            Thread.sleep(50);
         } catch (InterruptedException e) {}
         updateSdpRecords();
         return true;
@@ -602,7 +602,7 @@
         // Bluetooth stack need some a small delay here before adding more
         // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
         try {
-            Thread.sleep(20);
+            Thread.sleep(50);
         } catch (InterruptedException e) {}
 
         if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index fd709f2..457e66c 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -115,6 +115,45 @@
     public static final String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
 
     /**
+     * Starts an activity that will prompt the user for speech without requiring the user's
+     * visual attention or touch input. It will send it through a speech recognizer,
+     * and either synthesize speech for a web search result or trigger
+     * another type of action based on the user's speech.
+     *
+     * This activity may be launched while device is locked in a secure mode.
+     * Special care must be taken to ensure that the voice actions that are performed while
+     * hands free cannot compromise the device's security.
+     * The activity should check the value of the {@link #EXTRA_SECURE} extra to determine
+     * whether the device has been securely locked. If so, the activity should either restrict
+     * the set of voice actions that are permitted or require some form of secure
+     * authentication before proceeding.
+     *
+     * To ensure that the activity's user interface is visible while the lock screen is showing,
+     * the activity should set the
+     * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} window flag.
+     * Otherwise the activity's user interface may be hidden by the lock screen. The activity
+     * should take care not to leak private information when the device is securely locked.
+     *
+     * <p>Optional extras:
+     * <ul>
+     *   <li>{@link #EXTRA_SECURE}
+     * </ul>
+     */
+    public static final String ACTION_VOICE_SEARCH_HANDS_FREE =
+            "android.speech.action.VOICE_SEARCH_HANDS_FREE";
+
+    /**
+     * Optional boolean to indicate that a "hands free" voice search was performed while the device
+     * was in a secure mode. An example of secure mode is when the device's screen lock is active,
+     * and it requires some form of authentication to be unlocked.
+     *
+     * When the device is securely locked, the voice search activity should either restrict
+     * the set of voice actions that are permitted, or require some form of secure authentication
+     * before proceeding.
+     */
+    public static final String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
+
+    /**
      * The minimum length of an utterance. We will not stop recording before this amount of time.
      * 
      * Note that it is extremely rare you'd want to specify this value in an intent. If you don't
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index 386c866d..cd54f24 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -287,12 +287,12 @@
                     }
                 }
             }
-            while (start < textLength && mText.charAt(start) == '\n') {
-                start++;
-            }
             if (start < 0) {
                 return null;
             }
+            while (start < textLength && mText.charAt(start) == '\n') {
+                start++;
+            }
             int end = start;
             for (int i = end + 1; i < textLength; i++) {
                 end = i;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 825f351..aaa081c 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -24,16 +24,46 @@
 import android.util.Log;
 
 /**
- * Coordinates animations and drawing for UI on a particular thread.
- *
- * This object is thread-safe.  Other threads can post callbacks to run at a later time
- * on the UI thread.
- *
- * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
- * can only be accessed from the UI thread so operations that touch the event receiver
- * are posted to the UI thread if needed.
- *
- * @hide
+ * Coordinates the timing of animations, input and drawing.
+ * <p>
+ * The choreographer receives timing pulses (such as vertical synchronization)
+ * from the display subsystem then schedules work to occur as part of rendering
+ * the next display frame.
+ * </p><p>
+ * Applications typically interact with the choreographer indirectly using
+ * higher level abstractions in the animation framework or the view hierarchy.
+ * Here are some examples of things you can do using the higher-level APIs.
+ * </p>
+ * <ul>
+ * <li>To post an animation to be processed on a regular time basis synchronized with
+ * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
+ * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
+ * frame, use {@link View#postOnAnimation}.</li>
+ * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
+ * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
+ * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
+ * next display frame, use {@link View#postInvalidateOnAnimation()} or
+ * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
+ * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
+ * sync with display frame rendering, do nothing.  This already happens automatically.
+ * {@link View#onDraw} will be called at the appropriate time.</li>
+ * </ul>
+ * <p>
+ * However, there are a few cases where you might want to use the functions of the
+ * choreographer directly in your application.  Here are some examples.
+ * </p>
+ * <ul>
+ * <li>If your application does its rendering in a different thread, possibly using GL,
+ * or does not use the animation framework or view hierarchy at all
+ * and you want to ensure that it is appropriately synchronized with the display, then use
+ * {@link Choreographer#postFrameCallback}.</li>
+ * <li>... and that's about it.</li>
+ * </ul>
+ * <p>
+ * Each {@link Looper} thread has its own choreographer.  Other threads can
+ * post callbacks to run on the choreographer but they will run on the {@link Looper}
+ * to which the choreographer belongs.
+ * </p>
  */
 public final class Choreographer {
     private static final String TAG = "Choreographer";
@@ -79,13 +109,22 @@
     private static final int MSG_DO_SCHEDULE_VSYNC = 1;
     private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
 
+    // All frame callbacks posted by applications have this token.
+    private static final Object FRAME_CALLBACK_TOKEN = new Object() {
+        public String toString() { return "FRAME_CALLBACK_TOKEN"; }
+    };
+
     private final Object mLock = new Object();
 
     private final Looper mLooper;
     private final FrameHandler mHandler;
+
+    // The display event receiver can only be accessed by the looper thread to which
+    // it is attached.  We take care to ensure that we post message to the looper
+    // if appropriate when interacting with the display event receiver.
     private final FrameDisplayEventReceiver mDisplayEventReceiver;
 
-    private Callback mCallbackPool;
+    private CallbackRecord mCallbackPool;
 
     private final CallbackQueue[] mCallbackQueues;
 
@@ -96,17 +135,20 @@
 
     /**
      * Callback type: Input callback.  Runs first.
+     * @hide
      */
     public static final int CALLBACK_INPUT = 0;
 
     /**
      * Callback type: Animation callback.  Runs before traversals.
+     * @hide
      */
     public static final int CALLBACK_ANIMATION = 1;
 
     /**
      * Callback type: Traversal callback.  Handles layout and draw.  Runs last
      * after all other asynchronous messages have been handled.
+     * @hide
      */
     public static final int CALLBACK_TRAVERSAL = 2;
 
@@ -138,32 +180,38 @@
     }
 
     /**
-     * The amount of time, in milliseconds, between each frame of the animation. This is a
-     * requested time that the animation will attempt to honor, but the actual delay between
-     * frames may be different, depending on system load and capabilities. This is a static
+     * The amount of time, in milliseconds, between each frame of the animation.
+     * <p>
+     * This is a requested time that the animation will attempt to honor, but the actual delay
+     * between frames may be different, depending on system load and capabilities. This is a static
      * function because the same delay will be applied to all animations, since they are all
      * run off of a single timing loop.
-     *
+     * </p><p>
      * The frame delay may be ignored when the animation system uses an external timing
      * source, such as the display refresh rate (vsync), to govern animations.
+     * </p>
      *
      * @return the requested time between frames, in milliseconds
+     * @hide
      */
     public static long getFrameDelay() {
         return sFrameDelay;
     }
 
     /**
-     * The amount of time, in milliseconds, between each frame of the animation. This is a
-     * requested time that the animation will attempt to honor, but the actual delay between
-     * frames may be different, depending on system load and capabilities. This is a static
+     * The amount of time, in milliseconds, between each frame of the animation.
+     * <p>
+     * This is a requested time that the animation will attempt to honor, but the actual delay
+     * between frames may be different, depending on system load and capabilities. This is a static
      * function because the same delay will be applied to all animations, since they are all
      * run off of a single timing loop.
-     *
+     * </p><p>
      * The frame delay may be ignored when the animation system uses an external timing
      * source, such as the display refresh rate (vsync), to govern animations.
+     * </p>
      *
      * @param frameDelay the requested time between frames, in milliseconds
+     * @hide
      */
     public static void setFrameDelay(long frameDelay) {
         sFrameDelay = frameDelay;
@@ -171,23 +219,25 @@
 
     /**
      * Subtracts typical frame delay time from a delay interval in milliseconds.
-     *
+     * <p>
      * This method can be used to compensate for animation delay times that have baked
      * in assumptions about the frame delay.  For example, it's quite common for code to
      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
      * posting the animation callback but let the animation timer take care of the remaining
      * frame delay time.
-     *
+     * </p><p>
      * This method is somewhat conservative about how much of the frame delay it
      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
      * we might still wait 6ms before posting an animation callback that we want to run
      * on the next frame, but this is much better than waiting a whole 16ms and likely
      * missing the deadline.
+     * </p>
      *
      * @param delayMillis The original delay time including an assumed frame delay.
      * @return The adjusted delay time with the assumed frame delay subtracted out.
+     * @hide
      */
     public static long subtractFrameDelay(long delayMillis) {
         final long frameDelay = sFrameDelay;
@@ -196,21 +246,26 @@
 
     /**
      * Posts a callback to run on the next frame.
-     * The callback only runs once and then is automatically removed.
+     * <p>
+     * The callback runs once then is automatically removed.
+     * </p>
      *
      * @param callbackType The callback type.
      * @param action The callback action to run during the next frame.
      * @param token The callback token, or null if none.
      *
      * @see #removeCallbacks
+     * @hide
      */
     public void postCallback(int callbackType, Runnable action, Object token) {
         postCallbackDelayed(callbackType, action, token, 0);
     }
 
     /**
-     * Posts a callback to run on the next frame following the specified delay.
-     * The callback only runs once and then is automatically removed.
+     * Posts a callback to run on the next frame after the specified delay.
+     * <p>
+     * The callback runs once then is automatically removed.
+     * </p>
      *
      * @param callbackType The callback type.
      * @param action The callback action to run during the next frame after the specified delay.
@@ -218,6 +273,7 @@
      * @param delayMillis The delay time in milliseconds.
      *
      * @see #removeCallback
+     * @hide
      */
     public void postCallbackDelayed(int callbackType,
             Runnable action, Object token, long delayMillis) {
@@ -228,6 +284,11 @@
             throw new IllegalArgumentException("callbackType is invalid");
         }
 
+        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
+    }
+
+    private void postCallbackDelayedInternal(int callbackType,
+            Object action, Object token, long delayMillis) {
         if (DEBUG) {
             Log.d(TAG, "PostCallback: type=" + callbackType
                     + ", action=" + action + ", token=" + token
@@ -261,12 +322,17 @@
      *
      * @see #postCallback
      * @see #postCallbackDelayed
+     * @hide
      */
     public void removeCallbacks(int callbackType, Runnable action, Object token) {
         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
             throw new IllegalArgumentException("callbackType is invalid");
         }
 
+        removeCallbacksInternal(callbackType, action, token);
+    }
+
+    private void removeCallbacksInternal(int callbackType, Object action, Object token) {
         if (DEBUG) {
             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
                     + ", action=" + action + ", token=" + token);
@@ -281,17 +347,81 @@
     }
 
     /**
-     * Gets the time when the current frame started.  The frame time should be used
-     * instead of {@link SystemClock#uptimeMillis()} to synchronize animations.
-     * This helps to reduce inter-frame jitter because the frame time is fixed at the
-     * time the frame was scheduled to start, regardless of when the animations or
-     * drawing code actually ran.
+     * Posts a frame callback to run on the next frame.
+     * <p>
+     * The callback runs once then is automatically removed.
+     * </p>
      *
+     * @param callback The frame callback to run during the next frame.
+     *
+     * @see #postFrameCallbackDelayed
+     * @see #removeFrameCallback
+     */
+    public void postFrameCallback(FrameCallback callback) {
+        postFrameCallbackDelayed(callback, 0);
+    }
+
+    /**
+     * Posts a frame callback to run on the next frame after the specified delay.
+     * <p>
+     * The callback runs once then is automatically removed.
+     * </p>
+     *
+     * @param callback The frame callback to run during the next frame.
+     * @param delayMillis The delay time in milliseconds.
+     *
+     * @see #postFrameCallback
+     * @see #removeFrameCallback
+     */
+    public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+
+        postCallbackDelayedInternal(CALLBACK_ANIMATION,
+                callback, FRAME_CALLBACK_TOKEN, delayMillis);
+    }
+
+    /**
+     * Removes a previously posted frame callback.
+     *
+     * @param callback The frame callback to remove.
+     *
+     * @see #postFrameCallback
+     * @see #postFrameCallbackDelayed
+     */
+    public void removeFrameCallback(FrameCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+
+        removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
+    }
+
+    /**
+     * Gets the time when the current frame started.
+     * <p>
+     * This method provides the time in nanoseconds when the frame started being rendered.
+     * The frame time provides a stable time base for synchronizing animations
+     * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
+     * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
+     * time helps to reduce inter-frame jitter because the frame time is fixed at the time
+     * the frame was scheduled to start, regardless of when the animations or drawing
+     * callback actually runs.  All callbacks that run as part of rendering a frame will
+     * observe the same frame time so using the frame time also helps to synchronize effects
+     * that are performed by different callbacks.
+     * </p><p>
+     * Please note that the framework already takes care to process animations and
+     * drawing using the frame time as a stable time base.  Most applications should
+     * not need to use the frame time information directly.
+     * </p><p>
      * This method should only be called from within a callback.
+     * </p>
      *
      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
      *
      * @throws IllegalStateException if no frame is in progress.
+     * @hide
      */
     public long getFrameTime() {
         return getFrameTimeNanos() / NANOS_PER_MS;
@@ -303,6 +433,7 @@
      * @return The frame start time, in the {@link System#nanoTime()} time base.
      *
      * @throws IllegalStateException if no frame is in progress.
+     * @hide
      */
     public long getFrameTimeNanos() {
         synchronized (mLock) {
@@ -345,7 +476,7 @@
         }
     }
 
-    void doFrame(long timestampNanos, int frame) {
+    void doFrame(long frameTimeNanos, int frame) {
         final long startNanos;
         synchronized (mLock) {
             if (!mFrameScheduled) {
@@ -353,7 +484,7 @@
             }
 
             startNanos = System.nanoTime();
-            final long jitterNanos = startNanos - timestampNanos;
+            final long jitterNanos = startNanos - frameTimeNanos;
             if (jitterNanos >= mFrameIntervalNanos) {
                 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
                 if (DEBUG) {
@@ -363,10 +494,10 @@
                             + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                             + " ms in the past.");
                 }
-                timestampNanos = startNanos - lastFrameOffset;
+                frameTimeNanos = startNanos - lastFrameOffset;
             }
 
-            if (timestampNanos < mLastFrameTimeNanos) {
+            if (frameTimeNanos < mLastFrameTimeNanos) {
                 if (DEBUG) {
                     Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                             + "previously skipped frame.  Waiting for next vsync");
@@ -376,24 +507,27 @@
             }
 
             mFrameScheduled = false;
-            mLastFrameTimeNanos = timestampNanos;
+            mLastFrameTimeNanos = frameTimeNanos;
         }
 
-        doCallbacks(Choreographer.CALLBACK_INPUT);
-        doCallbacks(Choreographer.CALLBACK_ANIMATION);
-        doCallbacks(Choreographer.CALLBACK_TRAVERSAL);
+        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
 
         if (DEBUG) {
             final long endNanos = System.nanoTime();
             Log.d(TAG, "Frame " + frame + ": Finished, took "
                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
-                    + (startNanos - timestampNanos) * 0.000001f + " ms.");
+                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
         }
     }
 
-    void doCallbacks(int callbackType) {
-        Callback callbacks;
+    void doCallbacks(int callbackType, long frameTimeNanos) {
+        CallbackRecord callbacks;
         synchronized (mLock) {
+            // We use "now" to determine when callbacks become due because it's possible
+            // for earlier processing phases in a frame to post callbacks that should run
+            // in a following phase, such as an input event that causes an animation to start.
             final long now = SystemClock.uptimeMillis();
             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
             if (callbacks == null) {
@@ -402,19 +536,19 @@
             mCallbacksRunning = true;
         }
         try {
-            for (Callback c = callbacks; c != null; c = c.next) {
+            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                 if (DEBUG) {
                     Log.d(TAG, "RunCallback: type=" + callbackType
                             + ", action=" + c.action + ", token=" + c.token
                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                 }
-                c.action.run();
+                c.run(frameTimeNanos);
             }
         } finally {
             synchronized (mLock) {
                 mCallbacksRunning = false;
                 do {
-                    final Callback next = callbacks.next;
+                    final CallbackRecord next = callbacks.next;
                     recycleCallbackLocked(callbacks);
                     callbacks = next;
                 } while (callbacks != null);
@@ -449,10 +583,10 @@
         return Looper.myLooper() == mLooper;
     }
 
-    private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) {
-        Callback callback = mCallbackPool;
+    private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
+        CallbackRecord callback = mCallbackPool;
         if (callback == null) {
-            callback = new Callback();
+            callback = new CallbackRecord();
         } else {
             mCallbackPool = callback.next;
             callback.next = null;
@@ -463,13 +597,44 @@
         return callback;
     }
 
-    private void recycleCallbackLocked(Callback callback) {
+    private void recycleCallbackLocked(CallbackRecord callback) {
         callback.action = null;
         callback.token = null;
         callback.next = mCallbackPool;
         mCallbackPool = callback;
     }
 
+    /**
+     * Implement this interface to receive a callback when a new display frame is
+     * being rendered.  The callback is invoked on the {@link Looper} thread to
+     * which the {@link Choreographer} is attached.
+     */
+    public interface FrameCallback {
+        /**
+         * Called when a new display frame is being rendered.
+         * <p>
+         * This method provides the time in nanoseconds when the frame started being rendered.
+         * The frame time provides a stable time base for synchronizing animations
+         * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
+         * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
+         * time helps to reduce inter-frame jitter because the frame time is fixed at the time
+         * the frame was scheduled to start, regardless of when the animations or drawing
+         * callback actually runs.  All callbacks that run as part of rendering a frame will
+         * observe the same frame time so using the frame time also helps to synchronize effects
+         * that are performed by different callbacks.
+         * </p><p>
+         * Please note that the framework already takes care to process animations and
+         * drawing using the frame time as a stable time base.  Most applications should
+         * not need to use the frame time information directly.
+         * </p>
+         *
+         * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
+         * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
+         * to convert it to the {@link SystemClock#uptimeMillis()} time base.
+         */
+        public void doFrame(long frameTimeNanos);
+    }
+
     private final class FrameHandler extends Handler {
         public FrameHandler(Looper looper) {
             super(looper);
@@ -491,39 +656,65 @@
         }
     }
 
-    private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
+    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
+            implements Runnable {
+        private long mTimestampNanos;
+        private int mFrame;
+
         public FrameDisplayEventReceiver(Looper looper) {
             super(looper);
         }
 
         @Override
         public void onVsync(long timestampNanos, int frame) {
-            doFrame(timestampNanos, frame);
+            // Post the vsync event to the Handler.
+            // The idea is to prevent incoming vsync events from completely starving
+            // the message queue.  If there are no messages in the queue with timestamps
+            // earlier than the frame time, then the vsync event will be processed immediately.
+            // Otherwise, messages that predate the vsync event will be handled first.
+            mTimestampNanos = timestampNanos;
+            mFrame = frame;
+            Message msg = Message.obtain(mHandler, this);
+            msg.setAsynchronous(true);
+            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
+        }
+
+        @Override
+        public void run() {
+            doFrame(mTimestampNanos, mFrame);
         }
     }
 
-    private static final class Callback {
-        public Callback next;
+    private static final class CallbackRecord {
+        public CallbackRecord next;
         public long dueTime;
-        public Runnable action;
+        public Object action; // Runnable or FrameCallback
         public Object token;
+
+        public void run(long frameTimeNanos) {
+            if (token == FRAME_CALLBACK_TOKEN) {
+                ((FrameCallback)action).doFrame(frameTimeNanos);
+            } else {
+                ((Runnable)action).run();
+            }
+        }
     }
 
     private final class CallbackQueue {
-        private Callback mHead;
+        private CallbackRecord mHead;
 
         public boolean hasDueCallbacksLocked(long now) {
             return mHead != null && mHead.dueTime <= now;
         }
 
-        public Callback extractDueCallbacksLocked(long now) {
-            Callback callbacks = mHead;
+        public CallbackRecord extractDueCallbacksLocked(long now) {
+            CallbackRecord callbacks = mHead;
             if (callbacks == null || callbacks.dueTime > now) {
                 return null;
             }
 
-            Callback last = callbacks;
-            Callback next = last.next;
+            CallbackRecord last = callbacks;
+            CallbackRecord next = last.next;
             while (next != null) {
                 if (next.dueTime > now) {
                     last.next = null;
@@ -536,9 +727,9 @@
             return callbacks;
         }
 
-        public void addCallbackLocked(long dueTime, Runnable action, Object token) {
-            Callback callback = obtainCallbackLocked(dueTime, action, token);
-            Callback entry = mHead;
+        public void addCallbackLocked(long dueTime, Object action, Object token) {
+            CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
+            CallbackRecord entry = mHead;
             if (entry == null) {
                 mHead = callback;
                 return;
@@ -558,10 +749,10 @@
             entry.next = callback;
         }
 
-        public void removeCallbacksLocked(Runnable action, Object token) {
-            Callback predecessor = null;
-            for (Callback callback = mHead; callback != null;) {
-                final Callback next = callback.next;
+        public void removeCallbacksLocked(Object action, Object token) {
+            CallbackRecord predecessor = null;
+            for (CallbackRecord callback = mHead; callback != null;) {
+                final CallbackRecord next = callback.next;
                 if ((action == null || callback.action == action)
                         && (token == null || callback.token == token)) {
                     if (predecessor != null) {
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 3dab174..da666b5 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -83,6 +83,12 @@
     public abstract void invalidate();
 
     /**
+     * Clears additional resources held onto by this display list. You should
+     * only invoke this method after {@link #invalidate()}.
+     */
+    public abstract void clear();
+
+    /**
      * Returns whether the display list is currently usable. If this returns false,
      * the display list should be re-recorded prior to replaying it.
      *
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 0154556d..08a5831 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -72,6 +72,13 @@
     }
 
     @Override
+    public void clear() {
+        if (!mValid) {
+            mBitmaps.clear();
+        }
+    }
+
+    @Override
     public boolean isValid() {
         return mValid;
     }
@@ -343,7 +350,6 @@
     private static native void nSetPivotX(int displayList, float pivotX);
     private static native void nSetCaching(int displayList, boolean caching);
     private static native void nSetClipChildren(int displayList, boolean clipChildren);
-    private static native void nSetApplicationScale(int displayList, float scale);
     private static native void nSetAlpha(int displayList, float alpha);
     private static native void nSetHasOverlappingRendering(int displayList,
             boolean hasOverlappingRendering);
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 25d08ac..0114a41 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -585,8 +585,12 @@
             }
             // Hold the event we obtained above - listeners may have changed the original.
             mPreviousUpEvent = currentUpEvent;
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
+            if (mVelocityTracker != null) {
+                // This may have been cleared when we called out to the
+                // application above.
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
+            }
             mIsDoubleTapping = false;
             mHandler.removeMessages(SHOW_PRESS);
             mHandler.removeMessages(LONG_PRESS);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e25e2ef..f986d15 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -647,15 +647,10 @@
                 Log.d(LOG_TAG, "Disabling v-sync");
             }
 
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!ViewDebug.DEBUG_LATENCY) {
-                property = SystemProperties.get(PROFILE_PROPERTY, "false");
-                mProfileEnabled = "true".equalsIgnoreCase(property);
-                if (mProfileEnabled) {
-                    Log.d(LOG_TAG, "Profiling hardware renderer");
-                }
-            } else {
-                mProfileEnabled = true;
+            property = SystemProperties.get(PROFILE_PROPERTY, "false");
+            mProfileEnabled = "true".equalsIgnoreCase(property);
+            if (mProfileEnabled) {
+                Log.d(LOG_TAG, "Profiling hardware renderer");
             }
 
             if (mProfileEnabled) {
@@ -1132,11 +1127,6 @@
                             float total = (now - getDisplayListStartTime) * 0.000001f;
                             //noinspection PointlessArithmeticExpression
                             mProfileData[mProfileCurrentFrame] = total;
-
-                            if (ViewDebug.DEBUG_LATENCY) {
-                                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
-                                        total + "ms");
-                            }
                         }
 
                         if (displayList != null) {
@@ -1152,11 +1142,6 @@
                                 long now = System.nanoTime();
                                 float total = (now - drawDisplayListStartTime) * 0.000001f;
                                 mProfileData[mProfileCurrentFrame + 1] = total;
-
-                                if (ViewDebug.DEBUG_LATENCY) {
-                                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " +
-                                            total + "ms, status=" + status);
-                                }
                             }
 
                             handleFunctorStatus(attachInfo, status);
@@ -1198,11 +1183,6 @@
                         long now = System.nanoTime();
                         float total = (now - eglSwapBuffersStartTime) * 0.000001f;
                         mProfileData[mProfileCurrentFrame + 2] = total;
-
-                        if (ViewDebug.DEBUG_LATENCY) {
-                            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took " +
-                                    total + "ms");
-                        }
                     }
 
                     checkEglErrors();
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index c46e43a..a7ee12b 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -65,6 +65,7 @@
     private final Object[] mActionProviderConstructorArguments;
 
     private Context mContext;
+    private Object mRealOwner;
 
     /**
      * Constructs a menu inflater.
@@ -73,6 +74,20 @@
      */
     public MenuInflater(Context context) {
         mContext = context;
+        mRealOwner = context;
+        mActionViewConstructorArguments = new Object[] {context};
+        mActionProviderConstructorArguments = mActionViewConstructorArguments;
+    }
+
+    /**
+     * Constructs a menu inflater.
+     *
+     * @see Activity#getMenuInflater()
+     * @hide
+     */
+    public MenuInflater(Context context, Object realOwner) {
+        mContext = context;
+        mRealOwner = realOwner;
         mActionViewConstructorArguments = new Object[] {context};
         mActionProviderConstructorArguments = mActionViewConstructorArguments;
     }
@@ -190,12 +205,12 @@
             implements MenuItem.OnMenuItemClickListener {
         private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
         
-        private Context mContext;
+        private Object mRealOwner;
         private Method mMethod;
         
-        public InflatedOnMenuItemClickListener(Context context, String methodName) {
-            mContext = context;
-            Class<?> c = context.getClass();
+        public InflatedOnMenuItemClickListener(Object realOwner, String methodName) {
+            mRealOwner = realOwner;
+            Class<?> c = realOwner.getClass();
             try {
                 mMethod = c.getMethod(methodName, PARAM_TYPES);
             } catch (Exception e) {
@@ -210,9 +225,9 @@
         public boolean onMenuItemClick(MenuItem item) {
             try {
                 if (mMethod.getReturnType() == Boolean.TYPE) {
-                    return (Boolean) mMethod.invoke(mContext, item);
+                    return (Boolean) mMethod.invoke(mRealOwner, item);
                 } else {
-                    mMethod.invoke(mContext, item);
+                    mMethod.invoke(mRealOwner, item);
                     return true;
                 }
             } catch (Exception e) {
@@ -400,7 +415,7 @@
                             + "be used within a restricted context");
                 }
                 item.setOnMenuItemClickListener(
-                        new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));
+                        new InflatedOnMenuItemClickListener(mRealOwner, itemListenerMethodName));
             }
 
             if (item instanceof MenuItemImpl) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 2048de2..a719a01 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,6 +23,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -353,7 +354,12 @@
                     synchronized (mLock) {
                         mUpdateLayer = true;
                     }
-                    postInvalidate();
+
+                    if (Looper.myLooper() == Looper.getMainLooper()) {
+                        invalidate();
+                    } else {
+                        postInvalidate();
+                    }
                 }
             };
             mSurface.setOnFrameAvailableListener(mUpdateListener);
@@ -368,6 +374,14 @@
             // tell mLayer about it and set the SurfaceTexture to use the
             // current view size.
             mUpdateSurface = false;
+
+            // Since we are updating the layer, force an update to ensure its
+            // parameters are correct (width, height, transform, etc.)
+            synchronized (mLock) {
+                mUpdateLayer = true;
+            }
+            mMatrixChanged = true;
+
             mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
             nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
         }
@@ -465,7 +479,7 @@
     }
 
     private void applyTransformMatrix() {
-        if (mMatrixChanged) {
+        if (mMatrixChanged && mLayer != null) {
             mLayer.setTransform(mMatrix);
             mMatrixChanged = false;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a4fcd41..8cb5c85 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2255,9 +2255,27 @@
      * flags, we would like a stable view of the content insets given to
      * {@link #fitSystemWindows(Rect)}.  This means that the insets seen there
      * will always represent the worst case that the application can expect
-     * as a continue state.  In practice this means with any of system bar,
-     * nav bar, and status bar shown, but not the space that would be needed
-     * for an input method.
+     * as a continuous state.  In the stock Android UI this is the space for
+     * the system bar, nav bar, and status bar, but not more transient elements
+     * such as an input method.
+     *
+     * The stable layout your UI sees is based on the system UI modes you can
+     * switch to.  That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}
+     * then you will get a stable layout for changes of the
+     * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify
+     * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and
+     * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition
+     * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}
+     * with a stable layout.  (Note that you should avoid using
+     * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.)
+     *
+     * If you have set the window flag {@ WindowManager.LayoutParams#FLAG_FULLSCREEN}
+     * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}),
+     * then a hidden status bar will be considered a "stable" state for purposes
+     * here.  This allows your UI to continually hide the status bar, while still
+     * using the system UI flags to hide the action bar while still retaining
+     * a stable layout.  Note that changing the window fullscreen flag will never
+     * provide a stable layout for a clean transition.
      *
      * <p>If you are using ActionBar in
      * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
@@ -4307,7 +4325,6 @@
         if (gainFocus) {
             if (AccessibilityManager.getInstance(mContext).isEnabled()) {
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-                requestAccessibilityFocus();
             }
         }
 
@@ -4776,11 +4793,11 @@
             info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
         }
 
-        if (isClickable()) {
+        if (isClickable() && isEnabled()) {
             info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
         }
 
-        if (isLongClickable()) {
+        if (isLongClickable() && isEnabled()) {
             info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
         }
 
@@ -5237,12 +5254,25 @@
      * which you would like to ensure are not being covered.
      *
      * <p>The default implementation of this method simply applies the content
-     * inset's to the view's padding.  This can be enabled through
-     * {@link #setFitsSystemWindows(boolean)}.  Alternatively, you can override
-     * the method and handle the insets however you would like.  Note that the
-     * insets provided by the framework are always relative to the far edges
-     * of the window, not accounting for the location of the called view within
-     * that window.  (In fact when this method is called you do not yet know
+     * inset's to the view's padding, consuming that content (modifying the
+     * insets to be 0), and returning true.  This behavior is off by default, but can
+     * be enabled through {@link #setFitsSystemWindows(boolean)}.
+     *
+     * <p>This function's traversal down the hierarchy is depth-first.  The same content
+     * insets object is propagated down the hierarchy, so any changes made to it will
+     * be seen by all following views (including potentially ones above in
+     * the hierarchy since this is a depth-first traversal).  The first view
+     * that returns true will abort the entire traversal.
+     *
+     * <p>The default implementation works well for a situation where it is
+     * used with a container that covers the entire window, allowing it to
+     * apply the appropriate insets to its content on all edges.  If you need
+     * a more complicated layout (such as two different views fitting system
+     * windows, one on the top of the window, and one on the bottom),
+     * you can override the method and handle the insets however you would like.
+     * Note that the insets provided by the framework are always relative to the
+     * far edges of the window, not accounting for the location of the called view
+     * within that window.  (In fact when this method is called you do not yet know
      * where the layout will place the view, as it is done before layout happens.)
      *
      * <p>Note: unlike many View methods, there is no dispatch phase to this
@@ -5263,6 +5293,9 @@
      *
      * @return Return true if this view applied the insets and it should not
      * continue propagating further down the hierarchy, false otherwise.
+     * @see #getFitsSystemWindows()
+     * @see #setFitsSystemWindows()
+     * @see #setSystemUiVisibility(int)
      */
     protected boolean fitSystemWindows(Rect insets) {
         if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
@@ -5283,16 +5316,23 @@
     }
 
     /**
-     * Set whether or not this view should account for system screen decorations
-     * such as the status bar and inset its content. This allows this view to be
-     * positioned in absolute screen coordinates and remain visible to the user.
+     * Sets whether or not this view should account for system screen decorations
+     * such as the status bar and inset its content; that is, controlling whether
+     * the default implementation of {@link #fitSystemWindows(Rect)} will be
+     * executed.  See that method for more details.
      *
-     * <p>This should only be used by top-level window decor views.
+     * <p>Note that if you are providing your own implementation of
+     * {@link #fitSystemWindows(Rect)}, then there is no need to set this
+     * flag to true -- your implementation will be overriding the default
+     * implementation that checks this flag.
      *
-     * @param fitSystemWindows true to inset content for system screen decorations, false for
-     *                         default behavior.
+     * @param fitSystemWindows If true, then the default implementation of
+     * {@link #fitSystemWindows(Rect)} will be executed.
      *
      * @attr ref android.R.styleable#View_fitsSystemWindows
+     * @see #getFitsSystemWindows()
+     * @see #fitSystemWindows(Rect)
+     * @see #setSystemUiVisibility(int)
      */
     public void setFitsSystemWindows(boolean fitSystemWindows) {
         setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS);
@@ -5300,14 +5340,16 @@
 
     /**
      * Check for state of {@link #setFitsSystemWindows(boolean). If this method
-     * returns true, this view
-     * will account for system screen decorations such as the status bar and inset its
-     * content. This allows the view to be positioned in absolute screen coordinates
-     * and remain visible to the user.
+     * returns true, the default implementation of {@link #fitSystemWindows(Rect)}
+     * will be executed.
      *
-     * @return true if this view will adjust its content bounds for system screen decorations.
+     * @return Returns true if the default implementation of
+     * {@link #fitSystemWindows(Rect)} will be executed.
      *
      * @attr ref android.R.styleable#View_fitsSystemWindows
+     * @see #setFitsSystemWindows()
+     * @see #fitSystemWindows(Rect)
+     * @see #setSystemUiVisibility(int)
      */
     public boolean getFitsSystemWindows() {
         return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
@@ -6140,8 +6182,6 @@
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
             notifyAccessibilityStateChanged();
-            // Try to give input focus to this view - not a descendant.
-            requestFocusNoSearch(View.FOCUS_DOWN, null);
             return true;
         }
         return false;
@@ -6156,6 +6196,16 @@
      * @hide
      */
     public void clearAccessibilityFocus() {
+        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
+            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+            invalidate();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+            notifyAccessibilityStateChanged();
+            // Clear the text navigation state.
+            setAccessibilityCursorPosition(-1);
+        }
+        // Clear the global reference of accessibility focus if this
+        // view or any of its descendants had accessibility focus.
         ViewRootImpl viewRootImpl = getViewRootImpl();
         if (viewRootImpl != null) {
             View focusHost = viewRootImpl.getAccessibilityFocusedHost();
@@ -6163,34 +6213,18 @@
                 viewRootImpl.setAccessibilityFocusedHost(null);
             }
         }
-        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
-            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
-            invalidate();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
-            notifyAccessibilityStateChanged();
-
-            // Clear the text navigation state.
-            setAccessibilityCursorPosition(-1);
-
-            // Try to move accessibility focus to the input focus.
-            View rootView = getRootView();
-            if (rootView != null) {
-                View inputFocus = rootView.findFocus();
-                if (inputFocus != null) {
-                    inputFocus.requestAccessibilityFocus();
-                }
-            }
-        }
     }
 
     private void requestAccessibilityFocusFromHover() {
         if (includeForAccessibility() && isActionableForAccessibility()) {
             requestAccessibilityFocus();
+            requestFocusNoSearch(View.FOCUS_DOWN, null);
         } else {
             if (mParent != null) {
                 View nextFocus = mParent.findViewToTakeAccessibilityFocusFromHover(this, this);
                 if (nextFocus != null) {
                     nextFocus.requestAccessibilityFocus();
+                    nextFocus.requestFocusNoSearch(View.FOCUS_DOWN, null);
                 }
             }
         }
@@ -6637,7 +6671,7 @@
 
     private boolean nextAtGranularity(int granularity) {
         CharSequence text = getIterableTextForAccessibility();
-        if (text != null && text.length() > 0) {
+        if (text == null || text.length() == 0) {
             return false;
         }
         TextSegmentIterator iterator = getIteratorForGranularity(granularity);
@@ -6661,7 +6695,7 @@
 
     private boolean previousAtGranularity(int granularity) {
         CharSequence text = getIterableTextForAccessibility();
-        if (text != null && text.length() > 0) {
+        if (text == null || text.length() == 0) {
             return false;
         }
         TextSegmentIterator iterator = getIteratorForGranularity(granularity);
@@ -6766,6 +6800,8 @@
      */
     public void dispatchStartTemporaryDetach() {
         clearAccessibilityFocus();
+        clearDisplayList();
+
         onStartTemporaryDetach();
     }
 
@@ -9868,10 +9904,6 @@
      * @param dirty the rectangle representing the bounds of the dirty region
      */
     public void invalidate(Rect dirty) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
-        }
-
         if (skipInvalidate()) {
             return;
         }
@@ -9915,10 +9947,6 @@
      * @param b the bottom position of the dirty region
      */
     public void invalidate(int l, int t, int r, int b) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
-        }
-
         if (skipInvalidate()) {
             return;
         }
@@ -9971,10 +9999,6 @@
      * View's contents or dimensions have not changed.
      */
     void invalidate(boolean invalidateCache) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
-        }
-
         if (skipInvalidate()) {
             return;
         }
@@ -11433,10 +11457,8 @@
             }
             mAttachInfo.mViewRootImpl.cancelInvalidate(this);
         } else {
-            if (mDisplayList != null) {
-                // Should never happen
-                mDisplayList.invalidate();
-            }
+            // Should never happen
+            clearDisplayList();
         }
 
         mCurrentAnimation = null;
@@ -12214,6 +12236,13 @@
         return mDisplayList;
     }
 
+    private void clearDisplayList() {
+        if (mDisplayList != null) {
+            mDisplayList.invalidate();
+            mDisplayList.clear();
+        }
+    }
+
     /**
      * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
      *
@@ -12347,10 +12376,6 @@
                 mDrawingCache == null : mUnscaledDrawingCache == null)) {
             mCachingFailed = false;
 
-            if (ViewDebug.TRACE_HIERARCHY) {
-                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
-            }
-
             int width = mRight - mLeft;
             int height = mBottom - mTop;
 
@@ -12470,9 +12495,6 @@
 
             // Fast path for layouts with no backgrounds
             if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                if (ViewDebug.TRACE_HIERARCHY) {
-                    ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
-                }
                 mPrivateFlags &= ~DIRTY_MASK;
                 dispatchDraw(canvas);
             } else {
@@ -12710,6 +12732,7 @@
         if (!initialized) {
             a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
             a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
+            if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
             onAnimationStart();
         }
 
@@ -12723,6 +12746,7 @@
         } else {
             invalidationTransform = parent.mChildTransformation;
         }
+
         if (more) {
             if (!a.willChangeBounds()) {
                 if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
@@ -13086,9 +13110,6 @@
                 if (!hasDisplayList) {
                     // Fast path for layouts with no backgrounds
                     if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                        if (ViewDebug.TRACE_HIERARCHY) {
-                            ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW);
-                        }
                         mPrivateFlags &= ~DIRTY_MASK;
                         dispatchDraw(canvas);
                     } else {
@@ -13161,10 +13182,6 @@
      * @param canvas The Canvas to which the View is rendered.
      */
     public void draw(Canvas canvas) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
-        }
-
         final int privateFlags = mPrivateFlags;
         final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
                 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
@@ -13508,10 +13525,6 @@
         int oldR = mRight;
         boolean changed = setFrame(l, t, r, b);
         if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
-            if (ViewDebug.TRACE_HIERARCHY) {
-                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
-            }
-
             onLayout(changed, l, t, r, b);
             mPrivateFlags &= ~LAYOUT_REQUIRED;
 
@@ -14767,60 +14780,6 @@
     }
 
     /**
-     * @param consistency The type of consistency. See ViewDebug for more information.
-     *
-     * @hide
-     */
-    protected boolean dispatchConsistencyCheck(int consistency) {
-        return onConsistencyCheck(consistency);
-    }
-
-    /**
-     * Method that subclasses should implement to check their consistency. The type of
-     * consistency check is indicated by the bit field passed as a parameter.
-     *
-     * @param consistency The type of consistency. See ViewDebug for more information.
-     *
-     * @throws IllegalStateException if the view is in an inconsistent state.
-     *
-     * @hide
-     */
-    protected boolean onConsistencyCheck(int consistency) {
-        boolean result = true;
-
-        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
-        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
-
-        if (checkLayout) {
-            if (getParent() == null) {
-                result = false;
-                android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                        "View " + this + " does not have a parent.");
-            }
-
-            if (mAttachInfo == null) {
-                result = false;
-                android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                        "View " + this + " is not attached to a window.");
-            }
-        }
-
-        if (checkDrawing) {
-            // Do not check the DIRTY/DRAWN flags because views can call invalidate()
-            // from their draw() method
-
-            if ((mPrivateFlags & DRAWN) != DRAWN &&
-                    (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
-                result = false;
-                android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                        "View " + this + " was invalidated but its drawing cache is valid.");
-            }
-        }
-
-        return result;
-    }
-
-    /**
      * Prints information about this view in the log output, with the tag
      * {@link #VIEW_LOG_TAG}.
      *
@@ -14933,10 +14892,6 @@
      * tree.
      */
     public void requestLayout() {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
-        }
-
         mPrivateFlags |= FORCE_LAYOUT;
         mPrivateFlags |= INVALIDATED;
 
@@ -14987,10 +14942,6 @@
             // first clears the measured dimension flag
             mPrivateFlags &= ~MEASURED_DIMENSION_SET;
 
-            if (ViewDebug.TRACE_HIERARCHY) {
-                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
-            }
-
             // measure ourselves, this should set the measured dimension flag back
             onMeasure(widthMeasureSpec, heightMeasureSpec);
 
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9134966..823befb 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -193,19 +193,12 @@
     private static final int MAXIMUM_FLING_VELOCITY = 8000;
 
     /**
-     * Distance in dips between a touch up event denoting the end of a touch exploration
-     * gesture and the touch up event of a subsequent tap for the latter tap to be
-     * considered as a tap i.e. to perform a click.
-     */
-    private static final int TOUCH_EXPLORE_TAP_SLOP = 80;
-
-    /**
      * Delay before dispatching a recurring accessibility event in milliseconds.
      * This delay guarantees that a recurring event will be send at most once
      * during the {@link #SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS} time
      * frame.
      */
-    private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 400;
+    private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;
 
     /**
      * The maximum size of View's drawing cache, expressed in bytes. This size
@@ -238,7 +231,6 @@
     private final int mDoubleTapTouchSlop;
     private final int mPagingTouchSlop;
     private final int mDoubleTapSlop;
-    private final int mScaledTouchExploreTapSlop;
     private final int mWindowTouchSlop;
     private final int mMaximumDrawingCacheSize;
     private final int mOverscrollDistance;
@@ -265,7 +257,6 @@
         mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
         mPagingTouchSlop = PAGING_TOUCH_SLOP;
         mDoubleTapSlop = DOUBLE_TAP_SLOP;
-        mScaledTouchExploreTapSlop = TOUCH_EXPLORE_TAP_SLOP;
         mWindowTouchSlop = WINDOW_TOUCH_SLOP;
         //noinspection deprecation
         mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
@@ -302,7 +293,6 @@
         mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
-        mScaledTouchExploreTapSlop = (int) (density * TOUCH_EXPLORE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
 
         final Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
@@ -553,17 +543,6 @@
     }
 
     /**
-     * @return Distance in pixels between a touch up event denoting the end of a touch exploration
-     * gesture and the touch up event of a subsequent tap for the latter tap to be
-     * considered as a tap i.e. to perform a click.
-     *
-     * @hide
-     */
-    public int getScaledTouchExploreTapSlop() {
-        return mScaledTouchExploreTapSlop;
-    }
-
-    /**
      * Interval for dispatching a recurring accessibility event in milliseconds.
      * This interval guarantees that a recurring event will be send at most once
      * during the {@link #getSendRecurringAccessibilityEventsInterval()} time frame.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index cb37a1c..dd671dc 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -22,24 +22,14 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.Environment;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Printer;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -51,14 +41,8 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -67,107 +51,24 @@
  */
 public class ViewDebug {
     /**
-     * Log tag used to log errors related to the consistency of the view hierarchy.
-     *
-     * @hide
+     * @deprecated This flag is now unused
      */
-    public static final String CONSISTENCY_LOG_TAG = "ViewConsistency";
-
-    /**
-     * Flag indicating the consistency check should check layout-related properties.
-     *
-     * @hide
-     */
-    public static final int CONSISTENCY_LAYOUT = 0x1;
-
-    /**
-     * Flag indicating the consistency check should check drawing-related properties.
-     *
-     * @hide
-     */
-    public static final int CONSISTENCY_DRAWING = 0x2;
-
-    /**
-     * Enables or disables view hierarchy tracing. Any invoker of
-     * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first
-     * check that this value is set to true as not to affect performance.
-     */
+    @Deprecated
     public static final boolean TRACE_HIERARCHY = false;
 
     /**
-     * Enables or disables view recycler tracing. Any invoker of
-     * {@link #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])} should first
-     * check that this value is set to true as not to affect performance.
+     * @deprecated This flag is now unused
      */
+    @Deprecated
     public static final boolean TRACE_RECYCLER = false;
 
     /**
-     * Profiles drawing times in the events log.
-     *
-     * @hide
-     */
-    public static final boolean DEBUG_PROFILE_DRAWING = false;
-
-    /**
-     * Profiles layout times in the events log.
-     *
-     * @hide
-     */
-    public static final boolean DEBUG_PROFILE_LAYOUT = false;
-
-    /**
      * Enables detailed logging of drag/drop operations.
      * @hide
      */
     public static final boolean DEBUG_DRAG = false;
 
     /**
-     * Enables logging of factors that affect the latency and responsiveness of an application.
-     *
-     * Logs the relative difference between the time an event was created and the time it
-     * was delivered.
-     *
-     * Logs the time spent waiting for Surface.lockCanvas(), Surface.unlockCanvasAndPost()
-     * or eglSwapBuffers().  This is time that the event loop spends blocked and unresponsive.
-     * Ideally, drawing and animations should be perfectly synchronized with VSYNC so that
-     * dequeuing and queueing buffers is instantaneous.
-     *
-     * Logs the time spent in ViewRoot.performTraversals() and ViewRoot.performDraw().
-     * @hide
-     */
-    public static final boolean DEBUG_LATENCY = false;
-
-    /** @hide */
-    public static final String DEBUG_LATENCY_TAG = "ViewLatency";
-
-    /**
-     * Enables detailed logging of accessibility focus operations.
-     * @hide
-     */
-    public static final boolean DEBUG_ACCESSIBILITY_FOCUS = false;
-
-    /**
-     * Tag for logging of accessibility focus operations
-     * @hide
-     */
-    public static final String DEBUG_ACCESSIBILITY_FOCUS_TAG = "AccessibilityFocus";
-
-    /**
-     * <p>Enables or disables views consistency check. Even when this property is enabled,
-     * view consistency checks happen only if {@link false} is set
-     * to true. The value of this property can be configured externally in one of the
-     * following files:</p>
-     * <ul>
-     *  <li>/system/debug.prop</li>
-     *  <li>/debug.prop</li>
-     *  <li>/data/debug.prop</li>
-     * </ul>
-     * @hide
-     */
-    @Debug.DebugProperty
-    public static boolean consistencyCheckEnabled = false;
-
-    /**
      * This annotation can be used to mark fields and methods to be dumped by
      * the view server. Only non-void methods with no arguments can be annotated
      * by this annotation.
@@ -373,8 +274,9 @@
     private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
 
     /**
-     * Defines the type of hierarhcy trace to output to the hierarchy traces file.
+     * @deprecated This enum is now unused
      */
+    @Deprecated
     public enum HierarchyTraceType {
         INVALIDATE,
         INVALIDATE_CHILD,
@@ -386,13 +288,10 @@
         BUILD_CACHE
     }
 
-    private static BufferedWriter sHierarchyTraces;
-    private static ViewRootImpl sHierarchyRoot;
-    private static String sHierarchyTracePrefix;
-
     /**
-     * Defines the type of recycler trace to output to the recycler traces file.
+     * @deprecated This enum is now unused
      */
+    @Deprecated
     public enum RecyclerTraceType {
         NEW_VIEW,
         BIND_VIEW,
@@ -402,21 +301,6 @@
         MOVE_FROM_ACTIVE_TO_SCRAP_HEAP
     }
 
-    private static class RecyclerTrace {
-        public int view;
-        public RecyclerTraceType type;
-        public int position;
-        public int indexOnScreen;
-    }
-
-    private static View sRecyclerOwnerView;
-    private static List<View> sRecyclerViews;
-    private static List<RecyclerTrace> sRecyclerTraces;
-    private static String sRecyclerTracePrefix;
-
-    private static final ThreadLocal<LooperProfiler> sLooperProfilerStorage =
-            new ThreadLocal<LooperProfiler>();
-
     /**
      * Returns the number of instanciated Views.
      *
@@ -440,511 +324,50 @@
     }
 
     /**
-     * Starts profiling the looper associated with the current thread.
-     * You must call {@link #stopLooperProfiling} to end profiling
-     * and obtain the traces. Both methods must be invoked on the
-     * same thread.
-     * 
-     * @hide
+     * @deprecated This method is now unused and invoking it is a no-op
      */
-    public static void startLooperProfiling(String path, FileDescriptor fileDescriptor) {
-        if (sLooperProfilerStorage.get() == null) {
-            LooperProfiler profiler = new LooperProfiler(path, fileDescriptor);
-            sLooperProfilerStorage.set(profiler);
-            Looper.myLooper().setMessageLogging(profiler);
-        }
-    }    
-
-    /**
-     * Stops profiling the looper associated with the current thread.
-     * 
-     * @see #startLooperProfiling(String, java.io.FileDescriptor) 
-     * 
-     * @hide
-     */
-    public static void stopLooperProfiling() {
-        LooperProfiler profiler = sLooperProfilerStorage.get();
-        if (profiler != null) {
-            sLooperProfilerStorage.remove();
-            Looper.myLooper().setMessageLogging(null);
-            profiler.save();
-        }
-    }
-
-    private static class LooperProfiler implements Looper.Profiler, Printer {
-        private static final String LOG_TAG = "LooperProfiler";
-
-        private static final int TRACE_VERSION_NUMBER = 3;
-        private static final int ACTION_EXIT_METHOD = 0x1;
-        private static final int HEADER_SIZE = 32;
-        private static final String HEADER_MAGIC = "SLOW";
-        private static final short HEADER_RECORD_SIZE = (short) 14;
-
-        private final long mTraceWallStart;
-        private final long mTraceThreadStart;
-        
-        private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512);
-
-        private final HashMap<String, Integer> mTraceNames = new HashMap<String, Integer>(32);
-        private int mTraceId = 0;
-
-        private final String mPath;
-        private ParcelFileDescriptor mFileDescriptor;
-
-        LooperProfiler(String path, FileDescriptor fileDescriptor) {
-            mPath = path;
-            try {
-                mFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor);
-            } catch (IOException e) {
-                Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
-                throw new RuntimeException(e);
-            }
-            mTraceWallStart = SystemClock.currentTimeMicro();
-            mTraceThreadStart = SystemClock.currentThreadTimeMicro();            
-        }
-
-        @Override
-        public void println(String x) {
-            // Ignore messages
-        }
-
-        @Override
-        public void profile(Message message, long wallStart, long wallTime,
-                long threadStart, long threadTime) {
-            Entry entry = new Entry();
-            entry.traceId = getTraceId(message);
-            entry.wallStart = wallStart;
-            entry.wallTime = wallTime;
-            entry.threadStart = threadStart;
-            entry.threadTime = threadTime;
-
-            mTraces.add(entry);
-        }
-
-        private int getTraceId(Message message) {
-            String name = message.getTarget().getMessageName(message);
-            Integer traceId = mTraceNames.get(name);
-            if (traceId == null) {
-                traceId = mTraceId++ << 4;
-                mTraceNames.put(name, traceId);
-            }
-            return traceId;
-        }
-
-        void save() {
-            // Don't block the UI thread
-            new Thread(new Runnable() {
-                @Override
-                public void run() {
-                    saveTraces();
-                }
-            }, "LooperProfiler[" + mPath + "]").start();
-        }
-
-        private void saveTraces() {
-            FileOutputStream fos = new FileOutputStream(mFileDescriptor.getFileDescriptor());
-            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
-
-            try {
-                writeHeader(out, mTraceWallStart, mTraceNames, mTraces);
-                out.flush();
-
-                writeTraces(fos, out.size(), mTraceWallStart, mTraceThreadStart, mTraces);
-
-                Log.d(LOG_TAG, "Looper traces ready: " + mPath);
-            } catch (IOException e) {
-                Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
-            } finally {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
-                }
-                try {
-                    mFileDescriptor.close();
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
-                }
-            }
-        }
-        
-        private static void writeTraces(FileOutputStream out, long offset, long wallStart,
-                long threadStart, ArrayList<Entry> entries) throws IOException {
-    
-            FileChannel channel = out.getChannel();
-    
-            // Header
-            ByteBuffer buffer = ByteBuffer.allocateDirect(HEADER_SIZE);
-            buffer.put(HEADER_MAGIC.getBytes());
-            buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
-            buffer.putShort((short) TRACE_VERSION_NUMBER);    // version
-            buffer.putShort((short) HEADER_SIZE);             // offset to data
-            buffer.putLong(wallStart);                        // start time in usec
-            buffer.putShort(HEADER_RECORD_SIZE);              // size of a record in bytes
-            // padding to 32 bytes
-            for (int i = 0; i < HEADER_SIZE - 18; i++) {
-                buffer.put((byte) 0);
-            }
-    
-            buffer.flip();
-            channel.position(offset).write(buffer);
-            
-            buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN);
-            for (Entry entry : entries) {
-                buffer.putShort((short) 1);   // we simulate only one thread
-                buffer.putInt(entry.traceId); // entering method
-                buffer.putInt((int) (entry.threadStart - threadStart));
-                buffer.putInt((int) (entry.wallStart - wallStart));
-    
-                buffer.flip();
-                channel.write(buffer);
-                buffer.clear();
-    
-                buffer.putShort((short) 1);
-                buffer.putInt(entry.traceId | ACTION_EXIT_METHOD); // exiting method
-                buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart));
-                buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart));
-    
-                buffer.flip();
-                channel.write(buffer);
-                buffer.clear();
-            }
-    
-            channel.close();
-        }
-    
-        private static void writeHeader(DataOutputStream out, long start,
-                HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException {
-    
-            Entry last = entries.get(entries.size() - 1);
-            long wallTotal = (last.wallStart + last.wallTime) - start;
-    
-            startSection("version", out);
-            addValue(null, Integer.toString(TRACE_VERSION_NUMBER), out);
-            addValue("data-file-overflow", "false", out);
-            addValue("clock", "dual", out);
-            addValue("elapsed-time-usec", Long.toString(wallTotal), out);
-            addValue("num-method-calls", Integer.toString(entries.size()), out);
-            addValue("clock-call-overhead-nsec", "1", out);
-            addValue("vm", "dalvik", out);
-    
-            startSection("threads", out);
-            addThreadId(1, "main", out);
-    
-            startSection("methods", out);
-            addMethods(names, out);
-    
-            startSection("end", out);
-        }
-    
-        private static void addMethods(HashMap<String, Integer> names, DataOutputStream out)
-                throws IOException {
-    
-            for (Map.Entry<String, Integer> name : names.entrySet()) {
-                out.writeBytes(String.format("0x%08x\tEventQueue\t%s\t()V\tLooper\t-2\n",
-                        name.getValue(), name.getKey()));
-            }
-        }
-    
-        private static void addThreadId(int id, String name, DataOutputStream out)
-                throws IOException {
-
-            out.writeBytes(Integer.toString(id) + '\t' + name + '\n');
-        }
-    
-        private static void addValue(String name, String value, DataOutputStream out)
-                throws IOException {
-    
-            if (name != null) {
-                out.writeBytes(name + "=");
-            }
-            out.writeBytes(value + '\n');
-        }
-    
-        private static void startSection(String name, DataOutputStream out) throws IOException {
-            out.writeBytes("*" + name + '\n');
-        }
-
-        static class Entry {
-            int traceId;
-            long wallStart;
-            long wallTime;
-            long threadStart;
-            long threadTime;
-        }
-    }
-
-    /**
-     * Outputs a trace to the currently opened recycler traces. The trace records the type of
-     * recycler action performed on the supplied view as well as a number of parameters.
-     *
-     * @param view the view to trace
-     * @param type the type of the trace
-     * @param parameters parameters depending on the type of the trace
-     */
+    @Deprecated
+    @SuppressWarnings({ "UnusedParameters", "deprecation" })
     public static void trace(View view, RecyclerTraceType type, int... parameters) {
-        if (sRecyclerOwnerView == null || sRecyclerViews == null) {
-            return;
-        }
-
-        if (!sRecyclerViews.contains(view)) {
-            sRecyclerViews.add(view);
-        }
-
-        final int index = sRecyclerViews.indexOf(view);
-
-        RecyclerTrace trace = new RecyclerTrace();
-        trace.view = index;
-        trace.type = type;
-        trace.position = parameters[0];
-        trace.indexOnScreen = parameters[1];
-
-        sRecyclerTraces.add(trace);
     }
 
     /**
-     * Starts tracing the view recycler of the specified view. The trace is identified by a prefix,
-     * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and
-     * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>.
-     *
-     * Only one view recycler can be traced at the same time. After calling this method, any
-     * other invocation will result in a <code>IllegalStateException</code> unless
-     * {@link #stopRecyclerTracing()} is invoked before.
-     *
-     * Traces files are created only after {@link #stopRecyclerTracing()} is invoked.
-     *
-     * This method will return immediately if TRACE_RECYCLER is false.
-     *
-     * @param prefix the traces files name prefix
-     * @param view the view whose recycler must be traced
-     *
-     * @see #stopRecyclerTracing()
-     * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])
+     * @deprecated This method is now unused and invoking it is a no-op
      */
+    @Deprecated
+    @SuppressWarnings("UnusedParameters")
     public static void startRecyclerTracing(String prefix, View view) {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (!TRACE_RECYCLER) {
-            return;
-        }
-
-        if (sRecyclerOwnerView != null) {
-            throw new IllegalStateException("You must call stopRecyclerTracing() before running" +
-                " a new trace!");
-        }
-
-        sRecyclerTracePrefix = prefix;
-        sRecyclerOwnerView = view;
-        sRecyclerViews = new ArrayList<View>();
-        sRecyclerTraces = new LinkedList<RecyclerTrace>();
     }
 
     /**
-     * Stops the current view recycer tracing.
-     *
-     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code>
-     * containing all the traces (or method calls) relative to the specified view's recycler.
-     *
-     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>
-     * containing all of the views used by the recycler of the view supplied to
-     * {@link #startRecyclerTracing(String, View)}.
-     *
-     * This method will return immediately if TRACE_RECYCLER is false.
-     *
-     * @see #startRecyclerTracing(String, View)
-     * @see #trace(View, android.view.ViewDebug.RecyclerTraceType, int[])
+     * @deprecated This method is now unused and invoking it is a no-op
      */
+    @Deprecated
+    @SuppressWarnings("UnusedParameters")
     public static void stopRecyclerTracing() {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (!TRACE_RECYCLER) {
-            return;
-        }
-
-        if (sRecyclerOwnerView == null || sRecyclerViews == null) {
-            throw new IllegalStateException("You must call startRecyclerTracing() before" +
-                " stopRecyclerTracing()!");
-        }
-
-        File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
-        //noinspection ResultOfMethodCallIgnored
-        recyclerDump.mkdirs();
-
-        recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler");
-        try {
-            final BufferedWriter out = new BufferedWriter(new FileWriter(recyclerDump), 8 * 1024);
-
-            for (View view : sRecyclerViews) {
-                final String name = view.getClass().getName();
-                out.write(name);
-                out.newLine();
-            }
-
-            out.close();
-        } catch (IOException e) {
-            Log.e("View", "Could not dump recycler content");
-            return;
-        }
-
-        recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
-        recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
-        try {
-            if (recyclerDump.exists()) {
-                //noinspection ResultOfMethodCallIgnored
-                recyclerDump.delete();
-            }
-            final FileOutputStream file = new FileOutputStream(recyclerDump);
-            final DataOutputStream out = new DataOutputStream(file);
-
-            for (RecyclerTrace trace : sRecyclerTraces) {
-                out.writeInt(trace.view);
-                out.writeInt(trace.type.ordinal());
-                out.writeInt(trace.position);
-                out.writeInt(trace.indexOnScreen);
-                out.flush();
-            }
-
-            out.close();
-        } catch (IOException e) {
-            Log.e("View", "Could not dump recycler traces");
-            return;
-        }
-
-        sRecyclerViews.clear();
-        sRecyclerViews = null;
-
-        sRecyclerTraces.clear();
-        sRecyclerTraces = null;
-
-        sRecyclerOwnerView = null;
     }
 
     /**
-     * Outputs a trace to the currently opened traces file. The trace contains the class name
-     * and instance's hashcode of the specified view as well as the supplied trace type.
-     *
-     * @param view the view to trace
-     * @param type the type of the trace
+     * @deprecated This method is now unused and invoking it is a no-op
      */
+    @Deprecated
+    @SuppressWarnings({ "UnusedParameters", "deprecation" })
     public static void trace(View view, HierarchyTraceType type) {
-        if (sHierarchyTraces == null) {
-            return;
-        }
-
-        try {
-            sHierarchyTraces.write(type.name());
-            sHierarchyTraces.write(' ');
-            sHierarchyTraces.write(view.getClass().getName());
-            sHierarchyTraces.write('@');
-            sHierarchyTraces.write(Integer.toHexString(view.hashCode()));
-            sHierarchyTraces.newLine();
-        } catch (IOException e) {
-            Log.w("View", "Error while dumping trace of type " + type + " for view " + view);
-        }
     }
 
     /**
-     * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix,
-     * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and
-     * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>.
-     *
-     * Only one view hierarchy can be traced at the same time. After calling this method, any
-     * other invocation will result in a <code>IllegalStateException</code> unless
-     * {@link #stopHierarchyTracing()} is invoked before.
-     *
-     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>
-     * containing all the traces (or method calls) relative to the specified view's hierarchy.
-     *
-     * This method will return immediately if TRACE_HIERARCHY is false.
-     *
-     * @param prefix the traces files name prefix
-     * @param view the view whose hierarchy must be traced
-     *
-     * @see #stopHierarchyTracing()
-     * @see #trace(View, android.view.ViewDebug.HierarchyTraceType)
+     * @deprecated This method is now unused and invoking it is a no-op
      */
+    @Deprecated
+    @SuppressWarnings("UnusedParameters")
     public static void startHierarchyTracing(String prefix, View view) {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (!TRACE_HIERARCHY) {
-            return;
-        }
-
-        if (sHierarchyRoot != null) {
-            throw new IllegalStateException("You must call stopHierarchyTracing() before running" +
-                " a new trace!");
-        }
-
-        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
-        //noinspection ResultOfMethodCallIgnored
-        hierarchyDump.mkdirs();
-
-        hierarchyDump = new File(hierarchyDump, prefix + ".traces");
-        sHierarchyTracePrefix = prefix;
-
-        try {
-            sHierarchyTraces = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
-        } catch (IOException e) {
-            Log.e("View", "Could not dump view hierarchy");
-            return;
-        }
-
-        sHierarchyRoot = view.getViewRootImpl();
     }
 
     /**
-     * Stops the current view hierarchy tracing. This method closes the file
-     * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>.
-     *
-     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>
-     * containing the view hierarchy of the view supplied to
-     * {@link #startHierarchyTracing(String, View)}.
-     *
-     * This method will return immediately if TRACE_HIERARCHY is false.
-     *
-     * @see #startHierarchyTracing(String, View)
-     * @see #trace(View, android.view.ViewDebug.HierarchyTraceType)
+     * @deprecated This method is now unused and invoking it is a no-op
      */
+    @Deprecated
     public static void stopHierarchyTracing() {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (!TRACE_HIERARCHY) {
-            return;
-        }
-
-        if (sHierarchyRoot == null || sHierarchyTraces == null) {
-            throw new IllegalStateException("You must call startHierarchyTracing() before" +
-                " stopHierarchyTracing()!");
-        }
-
-        try {
-            sHierarchyTraces.close();
-        } catch (IOException e) {
-            Log.e("View", "Could not write view traces");
-        }
-        sHierarchyTraces = null;
-
-        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
-        //noinspection ResultOfMethodCallIgnored
-        hierarchyDump.mkdirs();
-        hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree");
-
-        BufferedWriter out;
-        try {
-            out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
-        } catch (IOException e) {
-            Log.e("View", "Could not dump view hierarchy");
-            return;
-        }
-
-        View view = sHierarchyRoot.getView();
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            dumpViewHierarchy(group, out, 0);
-            try {
-                out.close();
-            } catch (IOException e) {
-                Log.e("View", "Could not dump view hierarchy");
-            }
-        }
-
-        sHierarchyRoot = null;
     }
 
     static void dispatchCommand(View view, String command, String parameters,
@@ -1725,38 +1148,6 @@
         }
     }
 
-    private static void dumpViewHierarchy(ViewGroup group, BufferedWriter out, int level) {
-        if (!dumpView(group, out, level)) {
-            return;
-        }
-
-        final int count = group.getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View view = group.getChildAt(i);
-            if (view instanceof ViewGroup) {
-                dumpViewHierarchy((ViewGroup) view, out, level + 1);
-            } else {
-                dumpView(view, out, level + 1);
-            }
-        }
-    }
-
-    private static boolean dumpView(Object view, BufferedWriter out, int level) {
-        try {
-            for (int i = 0; i < level; i++) {
-                out.write(' ');
-            }
-            out.write(view.getClass().getName());
-            out.write('@');
-            out.write(Integer.toHexString(view.hashCode()));
-            out.newLine();
-        } catch (IOException e) {
-            Log.w("View", "Error while dumping hierarchy tree");
-            return false;
-        }
-        return true;
-    }
-
     private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
         if (mCapturedViewFieldsForClasses == null) {
             mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
@@ -1863,7 +1254,6 @@
     }
 
     private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
-
         if (obj == null) {
             return "null";
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b95ca5e..a243c73 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3154,8 +3154,12 @@
     }
 
     /**
-     * Adds a child view. If no layout parameters are already set on the child, the
-     * default parameters for this ViewGroup are set on the child.
+     * <p>Adds a child view. If no layout parameters are already set on the child, the
+     * default parameters for this ViewGroup are set on the child.</p>
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
      *
@@ -3168,6 +3172,10 @@
     /**
      * Adds a child view. If no layout parameters are already set on the child, the
      * default parameters for this ViewGroup are set on the child.
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
      * @param index the position at which to add the child
@@ -3189,6 +3197,10 @@
      * Adds a child view with this ViewGroup's default layout parameters and the
      * specified width and height.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      */
     public void addView(View child, int width, int height) {
@@ -3201,6 +3213,10 @@
     /**
      * Adds a child view with the specified layout parameters.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      * @param params the layout parameters to set on the child
      */
@@ -3211,6 +3227,10 @@
     /**
      * Adds a child view with the specified layout parameters.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      * @param index the position at which to add the child
      * @param params the layout parameters to set on the child
@@ -3528,6 +3548,10 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeView(View view) {
         removeViewInternal(view);
@@ -3539,6 +3563,10 @@
      * Removes a view during layout. This is useful if in your onLayout() method,
      * you need to remove more views.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     * 
      * @param view the view to remove from the group
      */
     public void removeViewInLayout(View view) {
@@ -3549,6 +3577,10 @@
      * Removes a range of views during layout. This is useful if in your onLayout() method,
      * you need to remove more views.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param start the index of the first view to remove from the group
      * @param count the number of views to remove from the group
      */
@@ -3559,6 +3591,10 @@
     /**
      * Removes the view at the specified position in the group.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     * 
      * @param index the position in the group of the view to remove
      */
     public void removeViewAt(int index) {
@@ -3570,6 +3606,10 @@
     /**
      * Removes the specified range of views from the group.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param start the first position in the group of the range of views to remove
      * @param count the number of views to remove
      */
@@ -3715,6 +3755,10 @@
     /**
      * Call this method to remove all child views from the
      * ViewGroup.
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeAllViews() {
         removeAllViewsInLayout();
@@ -3730,6 +3774,10 @@
      * that can currently fit inside the object on screen. Do not call
      * this method unless you are extending ViewGroup and understand the
      * view measuring and layout pipeline.
+     *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeAllViewsInLayout() {
         final int count = mChildrenCount;
@@ -3949,10 +3997,6 @@
      * the view hierarchy.
      */
     public final void invalidateChild(View child, final Rect dirty) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
-        }
-
         ViewParent parent = this;
 
         final AttachInfo attachInfo = mAttachInfo;
@@ -4045,10 +4089,6 @@
      * does not intersect with this ViewGroup's bounds.
      */
     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
-        if (ViewDebug.TRACE_HIERARCHY) {
-            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
-        }
-
         if ((mPrivateFlags & DRAWN) == DRAWN ||
                 (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
             if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
@@ -4631,61 +4671,6 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    protected boolean dispatchConsistencyCheck(int consistency) {
-        boolean result = super.dispatchConsistencyCheck(consistency);
-
-        final int count = mChildrenCount;
-        final View[] children = mChildren;
-        for (int i = 0; i < count; i++) {
-            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
-        }
-
-        return result;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    protected boolean onConsistencyCheck(int consistency) {
-        boolean result = super.onConsistencyCheck(consistency);
-
-        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
-        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
-
-        if (checkLayout) {
-            final int count = mChildrenCount;
-            final View[] children = mChildren;
-            for (int i = 0; i < count; i++) {
-                if (children[i].getParent() != this) {
-                    result = false;
-                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                            "View " + children[i] + " has no parent/a parent that is not " + this);
-                }
-            }
-        }
-
-        if (checkDrawing) {
-            // If this group is dirty, check that the parent is dirty as well
-            if ((mPrivateFlags & DIRTY_MASK) != 0) {
-                final ViewParent parent = getParent();
-                if (parent != null && !(parent instanceof ViewRootImpl)) {
-                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
-                        result = false;
-                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
-                    }
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /**
      * {@inheritDoc}
      */
     @Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bcd336d..551b6cc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -55,7 +55,6 @@
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
-import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TypedValue;
@@ -218,8 +217,6 @@
 
     boolean mTraversalScheduled;
     int mTraversalBarrier;
-    long mLastTraversalFinishedTimeNanos;
-    long mLastDrawFinishedTimeNanos;
     boolean mWillDrawSoon;
     boolean mFitSystemWindowsRequested;
     boolean mLayoutRequested;
@@ -987,18 +984,6 @@
                 Debug.startMethodTracing("ViewAncestor");
             }
 
-            final long traversalStartTime;
-            if (ViewDebug.DEBUG_LATENCY) {
-                traversalStartTime = System.nanoTime();
-                if (mLastTraversalFinishedTimeNanos != 0) {
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals(); it has been "
-                            + ((traversalStartTime - mLastTraversalFinishedTimeNanos) * 0.000001f)
-                            + "ms since the last traversals finished.");
-                } else {
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals().");
-                }
-            }
-
             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
             try {
                 performTraversals();
@@ -1006,14 +991,6 @@
                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
             }
 
-            if (ViewDebug.DEBUG_LATENCY) {
-                long now = System.nanoTime();
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performTraversals() took "
-                        + ((now - traversalStartTime) * 0.000001f)
-                        + "ms.");
-                mLastTraversalFinishedTimeNanos = now;
-            }
-
             if (mProfile) {
                 Debug.stopMethodTracing();
                 mProfile = false;
@@ -1076,7 +1053,7 @@
             if (baseSize != 0 && desiredWindowWidth > baseSize) {
                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-                host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
@@ -1087,7 +1064,7 @@
                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
                             + baseSize);
                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
-                    host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
@@ -1101,7 +1078,7 @@
         if (!goodMeasure) {
             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-            host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
                 windowSizeMayChange = true;
             }
@@ -1650,7 +1627,7 @@
                             + " coveredInsetsChanged=" + contentInsetsChanged);
     
                      // Ask host how big it wants to be
-                    host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
     
                     // Implementation of weights from WindowManager.LayoutParams
                     // We just grow the dimensions as needed and re-measure if
@@ -1676,7 +1653,7 @@
                         if (DEBUG_LAYOUT) Log.v(TAG,
                                 "And hey let's measure once more: width=" + width
                                 + " height=" + height);
-                        host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                     }
     
                     layoutRequested = true;
@@ -1688,28 +1665,7 @@
         boolean triggerGlobalLayoutListener = didLayout
                 || attachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
-            mLayoutRequested = false;
-            mScrollMayChange = true;
-            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
-                TAG, "Laying out " + host + " to (" +
-                host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
-            long startTime = 0L;
-            if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
-                startTime = SystemClock.elapsedRealtime();
-            }
-            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
-
-            if (false && ViewDebug.consistencyCheckEnabled) {
-                if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
-                    throw new IllegalStateException("The view hierarchy is an inconsistent state,"
-                            + "please refer to the logs with the tag "
-                            + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
-                }
-            }
-
-            if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
-                EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
-            }
+            performLayout();
 
             // By this point all views have been sized and positionned
             // We can compute the transparent area
@@ -1867,6 +1823,33 @@
         }
     }
 
+    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
+        try {
+            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
+    private void performLayout() {
+        mLayoutRequested = false;
+        mScrollMayChange = true;
+
+        final View host = mView;
+        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
+            Log.v(TAG, "Laying out " + host + " to (" +
+                    host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
+        try {
+            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
     public void requestTransparentRegion(View child) {
         // the test below should not fail unless someone is messing with us
         checkThread();
@@ -2008,18 +1991,6 @@
             return;
         }
 
-        final long drawStartTime;
-        if (ViewDebug.DEBUG_LATENCY) {
-            drawStartTime = System.nanoTime();
-            if (mLastDrawFinishedTimeNanos != 0) {
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting draw(); it has been "
-                        + ((drawStartTime - mLastDrawFinishedTimeNanos) * 0.000001f)
-                        + "ms since the last draw finished.");
-            } else {
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting draw().");
-            }
-        }
-
         final boolean fullRedrawNeeded = mFullRedrawNeeded;
         mFullRedrawNeeded = false;
 
@@ -2032,14 +2003,6 @@
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
 
-        if (ViewDebug.DEBUG_LATENCY) {
-            long now = System.nanoTime();
-            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performDraw() took "
-                    + ((now - drawStartTime) * 0.000001f)
-                    + "ms.");
-            mLastDrawFinishedTimeNanos = now;
-        }
-
         if (mReportNextDraw) {
             mReportNextDraw = false;
 
@@ -2203,19 +2166,8 @@
             int right = dirty.right;
             int bottom = dirty.bottom;
 
-            final long lockCanvasStartTime;
-            if (ViewDebug.DEBUG_LATENCY) {
-                lockCanvasStartTime = System.nanoTime();
-            }
-
             canvas = mSurface.lockCanvas(dirty);
 
-            if (ViewDebug.DEBUG_LATENCY) {
-                long now = System.nanoTime();
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
-                        + ((now - lockCanvasStartTime) * 0.000001f) + "ms");
-            }
-
             if (left != dirty.left || top != dirty.top || right != dirty.right ||
                     bottom != dirty.bottom) {
                 attachInfo.mIgnoreDirtyState = true;
@@ -2235,7 +2187,7 @@
             mLayoutRequested = true;    // ask wm for a new surface next time.
             return false;
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "IllegalArgumentException locking surface", e);
+            Log.e(TAG, "Could not lock surface", e);
             // Don't assume this is due to out of memory, it could be
             // something else, and if it is something else then we could
             // kill stuff (or ourself) for no reason.
@@ -2250,11 +2202,6 @@
                 //canvas.drawARGB(255, 255, 0, 0);
             }
 
-            long startTime = 0L;
-            if (ViewDebug.DEBUG_PROFILE_DRAWING) {
-                startTime = SystemClock.elapsedRealtime();
-            }
-
             // If this bitmap's format includes an alpha channel, we
             // need to clear it before drawing so that the child will
             // properly re-composite its drawing on a transparent
@@ -2287,46 +2234,23 @@
                         ? DisplayMetrics.DENSITY_DEVICE : 0);
                 attachInfo.mSetIgnoreDirtyState = false;
 
-                final long drawStartTime;
-                if (ViewDebug.DEBUG_LATENCY) {
-                    drawStartTime = System.nanoTime();
-                }
-
                 mView.draw(canvas);
 
                 drawAccessibilityFocusedDrawableIfNeeded(canvas);
-
-                if (ViewDebug.DEBUG_LATENCY) {
-                    long now = System.nanoTime();
-                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
-                            + ((now - drawStartTime) * 0.000001f) + "ms");
-                }
             } finally {
                 if (!attachInfo.mSetIgnoreDirtyState) {
                     // Only clear the flag if it was not set during the mView.draw() call
                     attachInfo.mIgnoreDirtyState = false;
                 }
             }
-
-            if (false && ViewDebug.consistencyCheckEnabled) {
-                mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
-            }
-
-            if (ViewDebug.DEBUG_PROFILE_DRAWING) {
-                EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
-            }
         } finally {
-            final long unlockCanvasAndPostStartTime;
-            if (ViewDebug.DEBUG_LATENCY) {
-                unlockCanvasAndPostStartTime = System.nanoTime();
-            }
-
-            surface.unlockCanvasAndPost(canvas);
-
-            if (ViewDebug.DEBUG_LATENCY) {
-                long now = System.nanoTime();
-                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
-                        + ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
+            try {
+                surface.unlockCanvasAndPost(canvas);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Could not unlock surface", e);
+                mLayoutRequested = true;    // ask wm for a new surface next time.
+                //noinspection ReturnInsideFinallyBlock
+                return false;
             }
 
             if (LOCAL_LOGV) {
@@ -2411,7 +2335,9 @@
         final int count = displayLists.size();
 
         for (int i = 0; i < count; i++) {
-            displayLists.get(i).invalidate();
+            final DisplayList displayList = displayLists.get(i);
+            displayList.invalidate();
+            displayList.clear();
         }
 
         displayLists.clear();
@@ -2971,20 +2897,6 @@
                         if (hasWindowFocus) {
                             mView.sendAccessibilityEvent(
                                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-                            // Give accessibility focus to the view that has input
-                            // focus if such, otherwise to the first one.
-                            if (mView instanceof ViewGroup) {
-                                ViewGroup viewGroup = (ViewGroup) mView;
-                                View focused = viewGroup.findFocus();
-                                if (focused != null) {
-                                    focused.requestAccessibilityFocus();
-                                }
-                            }
-                            // There is no accessibility focus, despite our effort
-                            // above, now just give it to the first view.
-                            if (mAccessibilityFocusedHost == null) {
-                                mView.requestAccessibilityFocus();
-                            }
                         }
                     }
                 }
@@ -3187,10 +3099,6 @@
     }
 
     private void deliverInputEvent(QueuedInputEvent q) {
-        if (ViewDebug.DEBUG_LATENCY) {
-            q.mDeliverTimeNanos = System.nanoTime();
-        }
-
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
         try {
             if (q.mEvent instanceof KeyEvent) {
@@ -3638,9 +3546,6 @@
 
     private void deliverKeyEventPostIme(QueuedInputEvent q) {
         final KeyEvent event = (KeyEvent)q.mEvent;
-        if (ViewDebug.DEBUG_LATENCY) {
-            q.mDeliverPostImeTimeNanos = System.nanoTime();
-        }
 
         // If the view went away, then the event will not be handled.
         if (mView == null || !mAdded) {
@@ -4163,11 +4068,6 @@
         public InputEvent mEvent;
         public InputEventReceiver mReceiver;
         public int mFlags;
-
-        // Used for latency calculations.
-        public long mReceiveTimeNanos;
-        public long mDeliverTimeNanos;
-        public long mDeliverPostImeTimeNanos;
     }
 
     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
@@ -4206,12 +4106,6 @@
             InputEventReceiver receiver, int flags, boolean processImmediately) {
         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
 
-        if (ViewDebug.DEBUG_LATENCY) {
-            q.mReceiveTimeNanos = System.nanoTime();
-            q.mDeliverTimeNanos = 0;
-            q.mDeliverPostImeTimeNanos = 0;
-        }
-
         // Always enqueue the input event in order, regardless of its time stamp.
         // We do this because the application or the IME may inject key events
         // in response to touch events and we want to ensure that the injected keys
@@ -4265,42 +4159,6 @@
             throw new IllegalStateException("finished input event out of order");
         }
 
-        if (ViewDebug.DEBUG_LATENCY) {
-            final long now = System.nanoTime();
-            final long eventTime = q.mEvent.getEventTimeNano();
-            final StringBuilder msg = new StringBuilder();
-            msg.append("Spent ");
-            msg.append((now - q.mReceiveTimeNanos) * 0.000001f);
-            msg.append("ms processing ");
-            if (q.mEvent instanceof KeyEvent) {
-                final KeyEvent  keyEvent = (KeyEvent)q.mEvent;
-                msg.append("key event, action=");
-                msg.append(KeyEvent.actionToString(keyEvent.getAction()));
-            } else {
-                final MotionEvent motionEvent = (MotionEvent)q.mEvent;
-                msg.append("motion event, action=");
-                msg.append(MotionEvent.actionToString(motionEvent.getAction()));
-                msg.append(", historySize=");
-                msg.append(motionEvent.getHistorySize());
-            }
-            msg.append(", handled=");
-            msg.append(handled);
-            msg.append(", received at +");
-            msg.append((q.mReceiveTimeNanos - eventTime) * 0.000001f);
-            if (q.mDeliverTimeNanos != 0) {
-                msg.append("ms, delivered at +");
-                msg.append((q.mDeliverTimeNanos - eventTime) * 0.000001f);
-            }
-            if (q.mDeliverPostImeTimeNanos != 0) {
-                msg.append("ms, delivered post IME at +");
-                msg.append((q.mDeliverPostImeTimeNanos - eventTime) * 0.000001f);
-            }
-            msg.append("ms, finished at +");
-            msg.append((now - eventTime) * 0.000001f);
-            msg.append("ms.");
-            Log.d(ViewDebug.DEBUG_LATENCY_TAG, msg.toString());
-        }
-
         if (q.mReceiver != null) {
             q.mReceiver.finishInputEvent(q.mEvent, handled);
         } else {
@@ -4447,6 +4305,7 @@
 
             for (int i = 0; i < viewCount; i++) {
                 mTempViews[i].invalidate();
+                mTempViews[i] = null;
             }
 
             for (int i = 0; i < viewRectCount; i++) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d62f513..d94275b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -691,13 +691,6 @@
          */
         public static final int FLAG_NEEDS_MENU_KEY = 0x08000000;
 
-        /** Window flag: *sigh* The lock screen wants to continue running its
-         * animation while it is fading.  A kind-of hack to allow this.  Maybe
-         * in the future we just make this the default behavior.
-         *
-         * {@hide} */
-        public static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000;
-        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 0c5d6ea..ceb9fe6 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -386,6 +386,12 @@
          */
         public InputChannel monitorInput(String name);
 
+        /**
+         * Switch the keyboard layout for the given device.
+         * Direction should be +1 or -1 to go to the next or previous keyboard layout.
+         */
+        public void switchKeyboardLayout(int deviceId, int direction);
+
         public void shutdown();
         public void rebootSafeMode();
     }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index d92ebcd..85d77cb 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
+import android.os.Handler;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -207,6 +208,11 @@
 
     private final CloseGuard guard = CloseGuard.get();
 
+    private Handler mListenerHandler;
+    private Runnable mOnStart;
+    private Runnable mOnRepeat;
+    private Runnable mOnEnd;
+
     /**
      * Creates a new animation with a duration of 0ms, the default interpolator, with
      * fillBefore set to true and fillAfter set to false
@@ -275,6 +281,7 @@
         mRepeated = 0;
         mMore = true;
         mOneMoreTime = true;
+        mListenerHandler = null;
     }
 
     /**
@@ -290,7 +297,7 @@
      */
     public void cancel() {
         if (mStarted && !mEnded) {
-            if (mListener != null) mListener.onAnimationEnd(this);
+            fireAnimationEnd();
             mEnded = true;
             guard.close();
         }
@@ -306,7 +313,7 @@
         if (mStarted && !mEnded) {
             mEnded = true;
             guard.close();
-            if (mListener != null) mListener.onAnimationEnd(this);
+            fireAnimationEnd();
         }
     }
 
@@ -341,6 +348,38 @@
     }
 
     /**
+     * Sets the handler used to invoke listeners.
+     * 
+     * @hide
+     */
+    public void setListenerHandler(Handler handler) {
+        if (mListenerHandler == null) {
+            mOnStart = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationStart(Animation.this);
+                    }
+                }
+            };
+            mOnRepeat = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationRepeat(Animation.this);
+                    }
+                }
+            };
+            mOnEnd = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationEnd(Animation.this);
+                    }
+                }
+            };
+        }
+        mListenerHandler = handler;
+    }
+
+    /**
      * Sets the acceleration curve for this animation. The interpolator is loaded as
      * a resource from the specified context.
      *
@@ -792,7 +831,6 @@
      * @return True if the animation is still running
      */
     public boolean getTransformation(long currentTime, Transformation outTransformation) {
-
         if (mStartTime == -1) {
             mStartTime = currentTime;
         }
@@ -815,9 +853,7 @@
 
         if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
             if (!mStarted) {
-                if (mListener != null) {
-                    mListener.onAnimationStart(this);
-                }
+                fireAnimationStart();
                 mStarted = true;
                 if (USE_CLOSEGUARD) {
                     guard.open("cancel or detach or getTransformation");
@@ -839,9 +875,7 @@
                 if (!mEnded) {
                     mEnded = true;
                     guard.close();
-                    if (mListener != null) {
-                        mListener.onAnimationEnd(this);
-                    }
+                    fireAnimationEnd();
                 }
             } else {
                 if (mRepeatCount > 0) {
@@ -855,9 +889,7 @@
                 mStartTime = -1;
                 mMore = true;
 
-                if (mListener != null) {
-                    mListener.onAnimationRepeat(this);
-                }
+                fireAnimationRepeat();
             }
         }
 
@@ -868,7 +900,28 @@
 
         return mMore;
     }
-    
+
+    private void fireAnimationStart() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationStart(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnStart);
+        }
+    }
+
+    private void fireAnimationRepeat() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationRepeat(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
+        }
+    }
+
+    private void fireAnimationEnd() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationEnd(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnEnd);
+        }
+    }
+
     /**
      * Gets the transformation to apply at a specified point in time. Implementations of this
      * method should always replace the specified Transformation or document they are doing
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1803352..d2cc2d8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -283,6 +283,7 @@
      * The InputConnection that was last retrieved from the served view.
      */
     InputConnection mServedInputConnection;
+    ControlledInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
      */
@@ -418,16 +419,22 @@
     
     private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
         private final InputMethodManager mParentInputMethodManager;
+        private boolean mActive;
 
         public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
                 final InputMethodManager inputMethodManager) {
             super(mainLooper, conn);
             mParentInputMethodManager = inputMethodManager;
+            mActive = true;
         }
 
         @Override
         public boolean isActive() {
-            return mParentInputMethodManager.mActive;
+            return mParentInputMethodManager.mActive && mActive;
+        }
+
+        void deactivate() {
+            mActive = false;
         }
     }
     
@@ -666,6 +673,10 @@
     void clearConnectionLocked() {
         mCurrentTextBoxAttribute = null;
         mServedInputConnection = null;
+        if (mServedInputConnectionWrapper != null) {
+            mServedInputConnectionWrapper.deactivate();
+            mServedInputConnectionWrapper = null;
+        }
     }
     
     /**
@@ -1060,7 +1071,7 @@
             // Notify the served view that its previous input connection is finished
             notifyInputConnectionFinished();
             mServedInputConnection = ic;
-            IInputContext servedContext;
+            ControlledInputConnectionWrapper servedContext;
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
                 mCursorSelEnd = tba.initialSelEnd;
@@ -1071,6 +1082,10 @@
             } else {
                 servedContext = null;
             }
+            if (mServedInputConnectionWrapper != null) {
+                mServedInputConnectionWrapper.deactivate();
+            }
+            mServedInputConnectionWrapper = servedContext;
             
             try {
                 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
@@ -1286,6 +1301,7 @@
         // we'll just do a window focus gain and call it a day.
         synchronized (mH) {
             try {
+                if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
                 mService.windowGainedFocus(mClient, rootView.getWindowToken(),
                         controlFlags, softInputMode, windowFlags, null, null);
             } catch (RemoteException e) {
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index f235295..c753188 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -146,7 +146,10 @@
         return false;
     }
 
-    private static Locale constructLocaleFromString(String localeStr) {
+    /**
+     * @hide
+     */
+    public static Locale constructLocaleFromString(String localeStr) {
         if (TextUtils.isEmpty(localeStr))
             return null;
         String[] localeParams = localeStr.split("_", 3);
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index 11bd815..cc490bd 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -16,484 +16,615 @@
 
 package android.webkit;
 
+import android.content.Context;
+import android.os.Bundle;
+import android.os.SystemClock;
 import android.provider.Settings;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.util.Log;
+import android.speech.tts.TextToSpeech;
 import android.view.KeyEvent;
-import android.view.accessibility.AccessibilityEvent;
+import android.view.View;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.webkit.WebViewCore.EventHub;
 
-import java.util.ArrayList;
-import java.util.Stack;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * This class injects accessibility into WebViews with disabled JavaScript or
- * WebViews with enabled JavaScript but for which we have no accessibility
- * script to inject.
- * </p>
- * Note: To avoid changes in the framework upon changing the available
- *       navigation axis, or reordering the navigation axis, or changing
- *       the key bindings, or defining sequence of actions to be bound to
- *       a given key this class is navigation axis agnostic. It is only
- *       aware of one navigation axis which is in fact the default behavior
- *       of webViews while using the DPAD/TrackBall.
- * </p>
- * In general a key binding is a mapping from modifiers + key code to
- * a sequence of actions. For more detail how to specify key bindings refer to
- * {@link android.provider.Settings.Secure#ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS}.
- * </p>
- * The possible actions are invocations to
- * {@link #setCurrentAxis(int, boolean, String)}, or
- * {@link #traverseCurrentAxis(int, boolean, String)}
- * {@link #traverseGivenAxis(int, int, boolean, String)}
- * {@link #prefromAxisTransition(int, int, boolean, String)}
- * referred via the values of:
- * {@link #ACTION_SET_CURRENT_AXIS},
- * {@link #ACTION_TRAVERSE_CURRENT_AXIS},
- * {@link #ACTION_TRAVERSE_GIVEN_AXIS},
- * {@link #ACTION_PERFORM_AXIS_TRANSITION},
- * respectively.
- * The arguments for the action invocation are specified as offset
- * hexademical pairs. Note the last argument of the invocation
- * should NOT be specified in the binding as it is provided by
- * this class. For details about the key binding implementation
- * refer to {@link AccessibilityWebContentKeyBinding}.
+ * Handles injecting accessibility JavaScript and related JavaScript -> Java
+ * APIs.
  */
 class AccessibilityInjector {
-    private static final String LOG_TAG = "AccessibilityInjector";
+    // Default result returned from AndroidVox. Using true here means if the
+    // script fails, an accessibility service will always think that traversal
+    // has succeeded.
+    private static final String DEFAULT_ANDROIDVOX_RESULT = "true";
 
-    private static final boolean DEBUG = true;
+    // The WebViewClassic this injector is responsible for managing.
+    private final WebViewClassic mWebViewClassic;
 
-    private static final int ACTION_SET_CURRENT_AXIS = 0;
-    private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
-    private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
-    private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
-    private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;
+    // Cached reference to mWebViewClassic.getContext(), for convenience.
+    private final Context mContext;
 
-    // the default WebView behavior abstracted as a navigation axis
-    private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
+    // Cached reference to mWebViewClassic.getWebView(), for convenience.
+    private final WebView mWebView;
 
-    // these are the same for all instances so make them process wide
-    private static ArrayList<AccessibilityWebContentKeyBinding> sBindings =
-        new ArrayList<AccessibilityWebContentKeyBinding>();
+    // The Java objects that are exposed to JavaScript.
+    private TextToSpeech mTextToSpeech;
+    private CallbackHandler mCallback;
 
-    // handle to the WebViewClassic this injector is associated with.
-    private final WebViewClassic mWebView;
+    // Lazily loaded helper objects.
+    private AccessibilityManager mAccessibilityManager;
+    private AccessibilityInjectorFallback mAccessibilityInjectorFallback;
+    private JSONObject mAccessibilityJSONObject;
 
-    // events scheduled for sending as soon as we receive the selected text
-    private final Stack<AccessibilityEvent> mScheduledEventStack = new Stack<AccessibilityEvent>();
+    // Whether the accessibility script has been injected into the current page.
+    private boolean mAccessibilityScriptInjected;
 
-    // the current traversal axis
-    private int mCurrentAxis = 2; // sentence
+    // Constants for determining script injection strategy.
+    private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
+    private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
+    @SuppressWarnings("unused")
+    private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
 
-    // we need to consume the up if we have handled the last down
-    private boolean mLastDownEventHandled;
+    // Alias for TTS API exposed to JavaScript.
+    private static final String ALIAS_TTS_JS_INTERFACE = "accessibility";
 
-    // getting two empty selection strings in a row we let the WebView handle the event
-    private boolean mIsLastSelectionStringNull;
+    // Alias for traversal callback exposed to JavaScript.
+    private static final String ALIAS_TRAVERSAL_JS_INTERFACE = "accessibilityTraversal";
 
-    // keep track of last direction
-    private int mLastDirection;
+    // Template for JavaScript that injects a screen-reader.
+    private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
+            "javascript:(function() {" +
+                    "    var chooser = document.createElement('script');" +
+                    "    chooser.type = 'text/javascript';" +
+                    "    chooser.src = '%1s';" +
+                    "    document.getElementsByTagName('head')[0].appendChild(chooser);" +
+                    "  })();";
+
+    // Template for JavaScript that performs AndroidVox actions.
+    private static final String ACCESSIBILITY_ANDROIDVOX_TEMPLATE =
+            "cvox.AndroidVox.performAction('%1s')";
 
     /**
-     * Creates a new injector associated with a given {@link WebViewClassic}.
+     * Creates an instance of the AccessibilityInjector based on
+     * {@code webViewClassic}.
      *
-     * @param webView The associated WebViewClassic.
+     * @param webViewClassic The WebViewClassic that this AccessibilityInjector
+     *            manages.
      */
-    public AccessibilityInjector(WebViewClassic webView) {
-        mWebView = webView;
-        ensureWebContentKeyBindings();
+    public AccessibilityInjector(WebViewClassic webViewClassic) {
+        mWebViewClassic = webViewClassic;
+        mWebView = webViewClassic.getWebView();
+        mContext = webViewClassic.getContext();
+        mAccessibilityManager = AccessibilityManager.getInstance(mContext);
     }
 
     /**
-     * Processes a key down <code>event</code>.
-     *
-     * @return True if the event was processed.
+     * Attempts to load scripting interfaces for accessibility.
+     * <p>
+     * This should be called when the window is attached.
+     * </p>
      */
-    public boolean onKeyEvent(KeyEvent event) {
-        // We do not handle ENTER in any circumstances.
-        if (isEnterActionKey(event.getKeyCode())) {
+    public void addAccessibilityApisIfNecessary() {
+        if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) {
+            return;
+        }
+
+        addTtsApis();
+        addCallbackApis();
+    }
+
+    /**
+     * Attempts to unload scripting interfaces for accessibility.
+     * <p>
+     * This should be called when the window is detached.
+     * </p>
+     */
+    public void removeAccessibilityApisIfNecessary() {
+        removeTtsApis();
+        removeCallbackApis();
+    }
+
+    /**
+     * Initializes an {@link AccessibilityNodeInfo} with the actions and
+     * movement granularity levels supported by this
+     * {@link AccessibilityInjector}.
+     * <p>
+     * If an action identifier is added in this method, this
+     * {@link AccessibilityInjector} should also return {@code true} from
+     * {@link #supportsAccessibilityAction(int)}.
+     * </p>
+     *
+     * @param info The info to initialize.
+     * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+     */
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+                | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
+        info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
+        info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
+        info.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
+        info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
+        info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+        info.setClickable(true);
+    }
+
+    /**
+     * Returns {@code true} if this {@link AccessibilityInjector} should handle
+     * the specified action.
+     *
+     * @param action An accessibility action identifier.
+     * @return {@code true} if this {@link AccessibilityInjector} should handle
+     *         the specified action.
+     */
+    public boolean supportsAccessibilityAction(int action) {
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
+            case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT:
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT:
+            case AccessibilityNodeInfo.ACTION_CLICK:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Performs the specified accessibility action.
+     *
+     * @param action The identifier of the action to perform.
+     * @param arguments The action arguments, or {@code null} if no arguments.
+     * @return {@code true} if the action was successful.
+     * @see View#performAccessibilityAction(int, Bundle)
+     */
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (!isAccessibilityEnabled()) {
+            mAccessibilityScriptInjected = false;
+            toggleFallbackAccessibilityInjector(false);
             return false;
         }
 
-        if (event.getAction() == KeyEvent.ACTION_UP) {
-            return mLastDownEventHandled;
+        if (mAccessibilityScriptInjected) {
+            return sendActionToAndroidVox(action, arguments);
+        }
+        
+        if (mAccessibilityInjectorFallback != null) {
+            return mAccessibilityInjectorFallback.performAccessibilityAction(action, arguments);
         }
 
-        mLastDownEventHandled = false;
+        return false;
+    }
 
-        AccessibilityWebContentKeyBinding binding = null;
-        for (AccessibilityWebContentKeyBinding candidate : sBindings) {
-            if (event.getKeyCode() == candidate.getKeyCode()
-                    && event.hasModifiers(candidate.getModifiers())) {
-                binding = candidate;
-                break;
+    /**
+     * Attempts to handle key events when accessibility is turned on.
+     *
+     * @param event The key event to handle.
+     * @return {@code true} if the event was handled.
+     */
+    public boolean handleKeyEventIfNecessary(KeyEvent event) {
+        if (!isAccessibilityEnabled()) {
+            mAccessibilityScriptInjected = false;
+            toggleFallbackAccessibilityInjector(false);
+            return false;
+        }
+
+        if (mAccessibilityScriptInjected) {
+            // if an accessibility script is injected we delegate to it the key
+            // handling. this script is a screen reader which is a fully fledged
+            // solution for blind users to navigate in and interact with web
+            // pages.
+            if (event.getAction() == KeyEvent.ACTION_UP) {
+                mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_UP, 0, 0, event);
+            } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                mWebViewClassic.sendBatchableInputMessage(EventHub.KEY_DOWN, 0, 0, event);
+            } else {
+                return false;
             }
+
+            return true;
         }
 
-        if (binding == null) {
+        if (mAccessibilityInjectorFallback != null) {
+            // if an accessibility injector is present (no JavaScript enabled or
+            // the site opts out injecting our JavaScript screen reader) we let
+            // it decide whether to act on and consume the event.
+            return mAccessibilityInjectorFallback.onKeyEvent(event);
+        }
+
+        return false;
+    }
+
+    /**
+     * Attempts to handle selection change events when accessibility is using a
+     * non-JavaScript method.
+     *
+     * @param selectionString The selection string.
+     */
+    public void handleSelectionChangedIfNecessary(String selectionString) {
+        if (mAccessibilityInjectorFallback != null) {
+            mAccessibilityInjectorFallback.onSelectionStringChange(selectionString);
+        }
+    }
+
+    /**
+     * Prepares for injecting accessibility scripts into a new page.
+     *
+     * @param url The URL that will be loaded.
+     */
+    public void onPageStarted(String url) {
+        mAccessibilityScriptInjected = false;
+    }
+
+    /**
+     * Attempts to inject the accessibility script using a {@code <script>} tag.
+     * <p>
+     * This should be called after a page has finished loading.
+     * </p>
+     *
+     * @param url The URL that just finished loading.
+     */
+    public void onPageFinished(String url) {
+        if (!isAccessibilityEnabled()) {
+            mAccessibilityScriptInjected = false;
+            toggleFallbackAccessibilityInjector(false);
+            return;
+        }
+
+        if (!shouldInjectJavaScript(url)) {
+            toggleFallbackAccessibilityInjector(true);
+            return;
+        }
+
+        toggleFallbackAccessibilityInjector(false);
+
+        final String injectionUrl = getScreenReaderInjectionUrl();
+        mWebView.loadUrl(injectionUrl);
+
+        mAccessibilityScriptInjected = true;
+    }
+
+    /**
+     * Toggles the non-JavaScript method for handling accessibility.
+     *
+     * @param enabled {@code true} to enable the non-JavaScript method, or
+     *            {@code false} to disable it.
+     */
+    private void toggleFallbackAccessibilityInjector(boolean enabled) {
+        if (enabled && (mAccessibilityInjectorFallback == null)) {
+            mAccessibilityInjectorFallback = new AccessibilityInjectorFallback(mWebViewClassic);
+        } else {
+            mAccessibilityInjectorFallback = null;
+        }
+    }
+
+    /**
+     * Determines whether it's okay to inject JavaScript into a given URL.
+     *
+     * @param url The URL to check.
+     * @return {@code true} if JavaScript should be injected, {@code false} if a
+     *         non-JavaScript method should be used.
+     */
+    private boolean shouldInjectJavaScript(String url) {
+        // Respect the WebView's JavaScript setting.
+        if (!isJavaScriptEnabled()) {
             return false;
         }
 
-        for (int i = 0, count = binding.getActionCount(); i < count; i++) {
-            int actionCode = binding.getActionCode(i);
-            String contentDescription = Integer.toHexString(binding.getAction(i));
-            switch (actionCode) {
-                case ACTION_SET_CURRENT_AXIS:
-                    int axis = binding.getFirstArgument(i);
-                    boolean sendEvent = (binding.getSecondArgument(i) == 1);
-                    setCurrentAxis(axis, sendEvent, contentDescription);
-                    mLastDownEventHandled = true;
-                    break;
-                case ACTION_TRAVERSE_CURRENT_AXIS:
-                    int direction = binding.getFirstArgument(i);
-                    // on second null selection string in same direction - WebView handles the event
-                    if (direction == mLastDirection && mIsLastSelectionStringNull) {
-                        mIsLastSelectionStringNull = false;
-                        return false;
-                    }
-                    mLastDirection = direction;
-                    sendEvent = (binding.getSecondArgument(i) == 1);
-                    mLastDownEventHandled = traverseCurrentAxis(direction, sendEvent,
-                            contentDescription);
-                    break;
-                case ACTION_TRAVERSE_GIVEN_AXIS:
-                    direction = binding.getFirstArgument(i);
-                    // on second null selection string in same direction => WebView handle the event
-                    if (direction == mLastDirection && mIsLastSelectionStringNull) {
-                        mIsLastSelectionStringNull = false;
-                        return false;
-                    }
-                    mLastDirection = direction;
-                    axis =  binding.getSecondArgument(i);
-                    sendEvent = (binding.getThirdArgument(i) == 1);
-                    traverseGivenAxis(direction, axis, sendEvent, contentDescription);
-                    mLastDownEventHandled = true;
-                    break;
-                case ACTION_PERFORM_AXIS_TRANSITION:
-                    int fromAxis = binding.getFirstArgument(i);
-                    int toAxis = binding.getSecondArgument(i);
-                    sendEvent = (binding.getThirdArgument(i) == 1);
-                    prefromAxisTransition(fromAxis, toAxis, sendEvent, contentDescription);
-                    mLastDownEventHandled = true;
-                    break;
-                case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS:
-                    // This is a special case since we treat the default WebView navigation
-                    // behavior as one of the possible navigation axis the user can use.
-                    // If we are not on the default WebView navigation axis this is NOP.
-                    if (mCurrentAxis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
-                        // While WebVew handles navigation we do not get null selection
-                        // strings so do not check for that here as the cases above.
-                        mLastDirection = binding.getFirstArgument(i);
-                        sendEvent = (binding.getSecondArgument(i) == 1);
-                        traverseGivenAxis(mLastDirection, NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR,
-                            sendEvent, contentDescription);
-                        mLastDownEventHandled = false;
-                    } else {
-                        mLastDownEventHandled = true;
-                    }
-                    break;
-                default:
-                    Log.w(LOG_TAG, "Unknown action code: " + actionCode);
-            }
-        }
-
-        return mLastDownEventHandled;
-    }
-
-    /**
-     * Set the current navigation axis which will be used while
-     * calling {@link #traverseCurrentAxis(int, boolean, String)}.
-     *
-     * @param axis The axis to set.
-     * @param sendEvent Whether to send an accessibility event to
-     *        announce the change.
-     */
-    private void setCurrentAxis(int axis, boolean sendEvent, String contentDescription) {
-        mCurrentAxis = axis;
-        if (sendEvent) {
-            AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent();
-            event.getText().add(String.valueOf(axis));
-            event.setContentDescription(contentDescription);
-            sendAccessibilityEvent(event);
-        }
-    }
-
-    /**
-     * Performs conditional transition one axis to another.
-     *
-     * @param fromAxis The axis which must be the current for the transition to occur.
-     * @param toAxis The axis to which to transition.
-     * @param sendEvent Flag if to send an event to announce successful transition.
-     * @param contentDescription A description of the performed action.
-     */
-    private void prefromAxisTransition(int fromAxis, int toAxis, boolean sendEvent,
-            String contentDescription) {
-        if (mCurrentAxis == fromAxis) {
-            setCurrentAxis(toAxis, sendEvent, contentDescription);
-        }
-    }
-
-    /**
-     * Traverse the document along the current navigation axis.
-     *
-     * @param direction The direction of traversal.
-     * @param sendEvent Whether to send an accessibility event to
-     *        announce the change.
-     * @param contentDescription A description of the performed action.
-     * @see #setCurrentAxis(int, boolean, String)
-     */
-    private boolean traverseCurrentAxis(int direction, boolean sendEvent,
-            String contentDescription) {
-        return traverseGivenAxis(direction, mCurrentAxis, sendEvent, contentDescription);
-    }
-
-    /**
-     * Traverse the document along the given navigation axis.
-     *
-     * @param direction The direction of traversal.
-     * @param axis The axis along which to traverse.
-     * @param sendEvent Whether to send an accessibility event to
-     *        announce the change.
-     * @param contentDescription A description of the performed action.
-     */
-    private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
-            String contentDescription) {
-        WebViewCore webViewCore = mWebView.getWebViewCore();
-        if (webViewCore == null) {
+        // Allow the page to opt out of Accessibility script injection.
+        if (getAxsUrlParameterValue(url) == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
             return false;
         }
 
-        AccessibilityEvent event = null;
-        if (sendEvent) {
-            event = getPartialyPopulatedAccessibilityEvent();
-            // the text will be set upon receiving the selection string
-            event.setContentDescription(contentDescription);
-        }
-        mScheduledEventStack.push(event);
-
-        // if the axis is the default let WebView handle the event which will
-        // result in cursor ring movement and selection of its content
-        if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+        // The user must explicitly enable Accessibility script injection.
+        if (!isScriptInjectionEnabled()) {
             return false;
         }
 
-        webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);
         return true;
     }
 
     /**
-     * Called when the <code>selectionString</code> has changed.
+     * @return {@code true} if the user has explicitly enabled Accessibility
+     *         script injection.
      */
-    public void onSelectionStringChange(String selectionString) {
-        if (DEBUG) {
-            Log.d(LOG_TAG, "Selection string: " + selectionString);
-        }
-        mIsLastSelectionStringNull = (selectionString == null);
-        if (mScheduledEventStack.isEmpty()) {
-            return;
-        }
-        AccessibilityEvent event = mScheduledEventStack.pop();
-        if (event != null) {
-            event.getText().add(selectionString);
-            sendAccessibilityEvent(event);
-        }
+    private boolean isScriptInjectionEnabled() {
+        final int injectionSetting = Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
+        return (injectionSetting == 1);
     }
 
     /**
-     * Sends an {@link AccessibilityEvent}.
+     * Attempts to initialize and add interfaces for TTS, if that hasn't already
+     * been done.
+     */
+    private void addTtsApis() {
+        if (mTextToSpeech != null) {
+            return;
+        }
+
+        final String pkgName = mContext.getPackageName();
+
+        mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true);
+        mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE);
+    }
+
+    /**
+     * Attempts to shutdown and remove interfaces for TTS, if that hasn't
+     * already been done.
+     */
+    private void removeTtsApis() {
+        if (mTextToSpeech == null) {
+            return;
+        }
+
+        mWebView.removeJavascriptInterface(ALIAS_TTS_JS_INTERFACE);
+        mTextToSpeech.stop();
+        mTextToSpeech.shutdown();
+        mTextToSpeech = null;
+    }
+
+    private void addCallbackApis() {
+        if (mCallback != null) {
+            return;
+        }
+
+        mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
+        mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE);
+    }
+
+    private void removeCallbackApis() {
+        if (mCallback == null) {
+            return;
+        }
+
+        mWebView.removeJavascriptInterface(ALIAS_TRAVERSAL_JS_INTERFACE);
+        mCallback = null;
+    }
+
+    /**
+     * Returns the script injection preference requested by the URL, or
+     * {@link #ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED} if the page has no
+     * preference.
      *
-     * @param event The event to send.
+     * @param url The URL to check.
+     * @return A script injection preference.
      */
-    private void sendAccessibilityEvent(AccessibilityEvent event) {
-        if (DEBUG) {
-            Log.d(LOG_TAG, "Dispatching: " + event);
-        }
-        // accessibility may be disabled while waiting for the selection string
-        AccessibilityManager accessibilityManager =
-            AccessibilityManager.getInstance(mWebView.getContext());
-        if (accessibilityManager.isEnabled()) {
-            accessibilityManager.sendAccessibilityEvent(event);
-        }
-    }
-
-    /**
-     * @return An accessibility event whose members are populated except its
-     *         text and content description.
-     */
-    private AccessibilityEvent getPartialyPopulatedAccessibilityEvent() {
-        AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        event.setClassName(mWebView.getClass().getName());
-        event.setPackageName(mWebView.getContext().getPackageName());
-        event.setEnabled(mWebView.getWebView().isEnabled());
-        return event;
-    }
-
-    /**
-     * Ensures that the Web content key bindings are loaded.
-     */
-    private void ensureWebContentKeyBindings() {
-        if (sBindings.size() > 0) {
-            return;
+    private int getAxsUrlParameterValue(String url) {
+        if (url == null) {
+            return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
         }
 
-        String webContentKeyBindingsString  = Settings.Secure.getString(
-                mWebView.getContext().getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
+        try {
+            final List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), null);
 
-        SimpleStringSplitter semiColonSplitter = new SimpleStringSplitter(';');
-        semiColonSplitter.setString(webContentKeyBindingsString);
-
-        while (semiColonSplitter.hasNext()) {
-            String bindingString = semiColonSplitter.next();
-            if (TextUtils.isEmpty(bindingString)) {
-                Log.e(LOG_TAG, "Disregarding malformed Web content key binding: "
-                        + webContentKeyBindingsString);
-                continue;
-            }
-            String[] keyValueArray = bindingString.split("=");
-            if (keyValueArray.length != 2) {
-                Log.e(LOG_TAG, "Disregarding malformed Web content key binding: " + bindingString);
-                continue;
-            }
-            try {
-                long keyCodeAndModifiers = Long.decode(keyValueArray[0].trim());
-                String[] actionStrings = keyValueArray[1].split(":");
-                int[] actions = new int[actionStrings.length];
-                for (int i = 0, count = actions.length; i < count; i++) {
-                    actions[i] = Integer.decode(actionStrings[i].trim());
+            for (NameValuePair param : params) {
+                if ("axs".equals(param.getName())) {
+                    return verifyInjectionValue(param.getValue());
                 }
-                sBindings.add(new AccessibilityWebContentKeyBinding(keyCodeAndModifiers, actions));
-            } catch (NumberFormatException nfe) {
-                Log.e(LOG_TAG, "Disregarding malformed key binding: " + bindingString);
             }
+        } catch (URISyntaxException e) {
+            // Do nothing.
         }
+
+        return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
     }
 
-    private boolean isEnterActionKey(int keyCode) {
-        return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
-                || keyCode == KeyEvent.KEYCODE_ENTER
-                || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
+    private int verifyInjectionValue(String value) {
+        try {
+            final int parsed = Integer.parseInt(value);
+
+            switch (parsed) {
+                case ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT:
+                    return ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT;
+                case ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED:
+                    return ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED;
+            }
+        } catch (NumberFormatException e) {
+            // Do nothing.
+        }
+
+        return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
     }
 
     /**
-     * Represents a web content key-binding.
+     * @return The URL for injecting the screen reader.
      */
-    private static final class AccessibilityWebContentKeyBinding {
+    private String getScreenReaderInjectionUrl() {
+        final String screenReaderUrl = Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
+        return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
+    }
 
-        private static final int MODIFIERS_OFFSET = 32;
-        private static final long MODIFIERS_MASK = 0xFFFFFFF00000000L;
+    /**
+     * @return {@code true} if JavaScript is enabled in the {@link WebView}
+     *         settings.
+     */
+    private boolean isJavaScriptEnabled() {
+        return mWebView.getSettings().getJavaScriptEnabled();
+    }
 
-        private static final int KEY_CODE_OFFSET = 0;
-        private static final long KEY_CODE_MASK = 0x00000000FFFFFFFFL;
+    /**
+     * @return {@code true} if accessibility is enabled.
+     */
+    private boolean isAccessibilityEnabled() {
+        return mAccessibilityManager.isEnabled();
+    }
 
-        private static final int ACTION_OFFSET = 24;
-        private static final int ACTION_MASK = 0xFF000000;
-
-        private static final int FIRST_ARGUMENT_OFFSET = 16;
-        private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
-
-        private static final int SECOND_ARGUMENT_OFFSET = 8;
-        private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
-
-        private static final int THIRD_ARGUMENT_OFFSET = 0;
-        private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
-
-        private final long mKeyCodeAndModifiers;
-
-        private final int [] mActionSequence;
-
-        /**
-         * @return The key code of the binding key.
-         */
-        public int getKeyCode() {
-            return (int) ((mKeyCodeAndModifiers & KEY_CODE_MASK) >> KEY_CODE_OFFSET);
-        }
-
-        /**
-         * @return The meta state of the binding key.
-         */
-        public int getModifiers() {
-            return (int) ((mKeyCodeAndModifiers & MODIFIERS_MASK) >> MODIFIERS_OFFSET);
-        }
-
-        /**
-         * @return The number of actions in the key binding.
-         */
-        public int getActionCount() {
-            return mActionSequence.length;
-        }
-
-        /**
-         * @param index The action for a given action <code>index</code>.
-         */
-        public int getAction(int index) {
-            return mActionSequence[index];
-        }
-
-        /**
-         * @param index The action code for a given action <code>index</code>.
-         */
-        public int getActionCode(int index) {
-            return (mActionSequence[index] & ACTION_MASK) >> ACTION_OFFSET;
-        }
-
-        /**
-         * @param index The first argument for a given action <code>index</code>.
-         */
-        public int getFirstArgument(int index) {
-            return (mActionSequence[index] & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
-        }
-
-        /**
-         * @param index The second argument for a given action <code>index</code>.
-         */
-        public int getSecondArgument(int index) {
-            return (mActionSequence[index] & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
-        }
-
-        /**
-         * @param index The third argument for a given action <code>index</code>.
-         */
-        public int getThirdArgument(int index) {
-            return (mActionSequence[index] & THIRD_ARGUMENT_MASK) >> THIRD_ARGUMENT_OFFSET;
-        }
-
-        /**
-         * Creates a new instance.
-         * @param keyCodeAndModifiers The key for the binding (key and modifiers).
-         * @param actionSequence The sequence of action for the binding.
-         */
-        public AccessibilityWebContentKeyBinding(long keyCodeAndModifiers, int[] actionSequence) {
-            mKeyCodeAndModifiers = keyCodeAndModifiers;
-            mActionSequence = actionSequence;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("modifiers: ");
-            builder.append(getModifiers());
-            builder.append(", keyCode: ");
-            builder.append(getKeyCode());
-            builder.append(", actions[");
-            for (int i = 0, count = getActionCount(); i < count; i++) {
-                builder.append("{actionCode");
-                builder.append(i);
-                builder.append(": ");
-                builder.append(getActionCode(i));
-                builder.append(", firstArgument: ");
-                builder.append(getFirstArgument(i));
-                builder.append(", secondArgument: ");
-                builder.append(getSecondArgument(i));
-                builder.append(", thirdArgument: ");
-                builder.append(getThirdArgument(i));
-                builder.append("}");
+    /**
+     * Packs an accessibility action into a JSON object and sends it to AndroidVox.
+     *
+     * @param action The action identifier.
+     * @param arguments The action arguments, if applicable.
+     * @return The result of the action.
+     */
+    private boolean sendActionToAndroidVox(int action, Bundle arguments) {
+        if (mAccessibilityJSONObject == null) {
+            mAccessibilityJSONObject = new JSONObject();
+        } else {
+            // Remove all keys from the object.
+            final Iterator<?> keys = mAccessibilityJSONObject.keys();
+            while (keys.hasNext()) {
+                keys.next();
+                keys.remove();
             }
-            builder.append("]");
-            return builder.toString();
+        }
+
+        try {
+            mAccessibilityJSONObject.accumulate("action", action);
+
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+                case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
+                    final int granularity = arguments.getInt(
+                            AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
+                    mAccessibilityJSONObject.accumulate("granularity", granularity);
+                    break;
+                case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT:
+                case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT:
+                    final String element = arguments.getString(
+                            AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
+                    mAccessibilityJSONObject.accumulate("element", element);
+                    break;
+            }
+        } catch (JSONException e) {
+            return false;
+        }
+
+        final String jsonString = mAccessibilityJSONObject.toString();
+        final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString);
+        final String result = mCallback.performAction(mWebView, jsCode, DEFAULT_ANDROIDVOX_RESULT);
+
+        return ("true".equalsIgnoreCase(result));
+    }
+
+    /**
+     * Exposes result interface to JavaScript.
+     */
+    private static class CallbackHandler {
+        private static final String JAVASCRIPT_ACTION_TEMPLATE =
+                "javascript:(function() { %s.onResult(%d, %s); })();";
+
+        // Time in milliseconds to wait for a result before failing.
+        private static final long RESULT_TIMEOUT = 200;
+
+        private final AtomicInteger mResultIdCounter = new AtomicInteger();
+        private final Object mResultLock = new Object();
+        private final String mInterfaceName;
+
+        private String mResult = null;
+        private long mResultId = -1;
+
+        private CallbackHandler(String interfaceName) {
+            mInterfaceName = interfaceName;
+        }
+
+        /**
+         * Performs an action and attempts to wait for a result.
+         *
+         * @param webView The WebView to perform the action on.
+         * @param code JavaScript code that evaluates to a result.
+         * @param defaultResult The result to return if the action times out.
+         * @return The result of the action, or false if it timed out.
+         */
+        private String performAction(WebView webView, String code, String defaultResult) {
+            final int resultId = mResultIdCounter.getAndIncrement();
+            final String url = String.format(
+                    JAVASCRIPT_ACTION_TEMPLATE, mInterfaceName, resultId, code);
+            webView.loadUrl(url);
+
+            return getResultAndClear(resultId, defaultResult);
+        }
+
+        /**
+         * Gets the result of a request to perform an accessibility action.
+         *
+         * @param resultId The result id to match the result with the request.
+         * @param defaultResult The default result to return on timeout.
+         * @return The result of the request.
+         */
+        private String getResultAndClear(int resultId, String defaultResult) {
+            synchronized (mResultLock) {
+                final boolean success = waitForResultTimedLocked(resultId);
+                final String result = success ? mResult : defaultResult;
+                clearResultLocked();
+                return result;
+            }
+        }
+
+        /**
+         * Clears the result state.
+         */
+        private void clearResultLocked() {
+            mResultId = -1;
+            mResult = null;
+        }
+
+        /**
+         * Waits up to a given bound for a result of a request and returns it.
+         *
+         * @param resultId The result id to match the result with the request.
+         * @return Whether the result was received.
+         */
+        private boolean waitForResultTimedLocked(int resultId) {
+            long waitTimeMillis = RESULT_TIMEOUT;
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                try {
+                    if (mResultId == resultId) {
+                        return true;
+                    }
+                    if (mResultId > resultId) {
+                        return false;
+                    }
+                    final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                    waitTimeMillis = RESULT_TIMEOUT - elapsedTimeMillis;
+                    if (waitTimeMillis <= 0) {
+                        return false;
+                    }
+                    mResultLock.wait(waitTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+
+        /**
+         * Callback exposed to JavaScript. Handles returning the result of a
+         * request to a waiting (or potentially timed out) thread.
+         *
+         * @param id The result id of the request as a {@link String}.
+         * @param result The result of the request as a {@link String}.
+         */
+        @SuppressWarnings("unused")
+        public void onResult(String id, String result) {
+            final long resultId;
+
+            try {
+                resultId = Long.parseLong(id);
+            } catch (NumberFormatException e) {
+                return;
+            }
+
+            synchronized (mResultLock) {
+                if (resultId > mResultId) {
+                    mResult = result;
+                    mResultId = resultId;
+                }
+                mResultLock.notifyAll();
+            }
         }
     }
 }
diff --git a/core/java/android/webkit/AccessibilityInjectorFallback.java b/core/java/android/webkit/AccessibilityInjectorFallback.java
new file mode 100644
index 0000000..4d9c26c
--- /dev/null
+++ b/core/java/android/webkit/AccessibilityInjectorFallback.java
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2010 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.webkit;
+
+import android.os.Bundle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.webkit.WebViewCore.EventHub;
+
+import java.util.ArrayList;
+import java.util.Stack;
+
+/**
+ * This class injects accessibility into WebViews with disabled JavaScript or
+ * WebViews with enabled JavaScript but for which we have no accessibility
+ * script to inject.
+ * </p>
+ * Note: To avoid changes in the framework upon changing the available
+ *       navigation axis, or reordering the navigation axis, or changing
+ *       the key bindings, or defining sequence of actions to be bound to
+ *       a given key this class is navigation axis agnostic. It is only
+ *       aware of one navigation axis which is in fact the default behavior
+ *       of webViews while using the DPAD/TrackBall.
+ * </p>
+ * In general a key binding is a mapping from modifiers + key code to
+ * a sequence of actions. For more detail how to specify key bindings refer to
+ * {@link android.provider.Settings.Secure#ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS}.
+ * </p>
+ * The possible actions are invocations to
+ * {@link #setCurrentAxis(int, boolean, String)}, or
+ * {@link #traverseCurrentAxis(int, boolean, String)}
+ * {@link #traverseGivenAxis(int, int, boolean, String)}
+ * {@link #performAxisTransition(int, int, boolean, String)}
+ * referred via the values of:
+ * {@link #ACTION_SET_CURRENT_AXIS},
+ * {@link #ACTION_TRAVERSE_CURRENT_AXIS},
+ * {@link #ACTION_TRAVERSE_GIVEN_AXIS},
+ * {@link #ACTION_PERFORM_AXIS_TRANSITION},
+ * respectively.
+ * The arguments for the action invocation are specified as offset
+ * hexademical pairs. Note the last argument of the invocation
+ * should NOT be specified in the binding as it is provided by
+ * this class. For details about the key binding implementation
+ * refer to {@link AccessibilityWebContentKeyBinding}.
+ */
+class AccessibilityInjectorFallback {
+    private static final String LOG_TAG = "AccessibilityInjector";
+
+    private static final boolean DEBUG = true;
+
+    private static final int ACTION_SET_CURRENT_AXIS = 0;
+    private static final int ACTION_TRAVERSE_CURRENT_AXIS = 1;
+    private static final int ACTION_TRAVERSE_GIVEN_AXIS = 2;
+    private static final int ACTION_PERFORM_AXIS_TRANSITION = 3;
+    private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4;
+
+    // WebView navigation axes from WebViewCore.h, plus an additional axis for
+    // the default behavior.
+    private static final int NAVIGATION_AXIS_CHARACTER = 0;
+    private static final int NAVIGATION_AXIS_WORD = 1;
+    private static final int NAVIGATION_AXIS_SENTENCE = 2;
+    @SuppressWarnings("unused")
+    private static final int NAVIGATION_AXIS_HEADING = 3;
+    private static final int NAVIGATION_AXIS_SIBLING = 5;
+    @SuppressWarnings("unused")
+    private static final int NAVIGATION_AXIS_PARENT_FIRST_CHILD = 5;
+    private static final int NAVIGATION_AXIS_DOCUMENT = 6;
+    private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7;
+
+    // WebView navigation directions from WebViewCore.h.
+    private static final int NAVIGATION_DIRECTION_BACKWARD = 0;
+    private static final int NAVIGATION_DIRECTION_FORWARD = 1;
+
+    // these are the same for all instances so make them process wide
+    private static ArrayList<AccessibilityWebContentKeyBinding> sBindings =
+        new ArrayList<AccessibilityWebContentKeyBinding>();
+
+    // handle to the WebViewClassic this injector is associated with.
+    private final WebViewClassic mWebView;
+    private final WebView mWebViewInternal;
+
+    // events scheduled for sending as soon as we receive the selected text
+    private final Stack<AccessibilityEvent> mScheduledEventStack = new Stack<AccessibilityEvent>();
+
+    // the current traversal axis
+    private int mCurrentAxis = 2; // sentence
+
+    // we need to consume the up if we have handled the last down
+    private boolean mLastDownEventHandled;
+
+    // getting two empty selection strings in a row we let the WebView handle the event
+    private boolean mIsLastSelectionStringNull;
+
+    // keep track of last direction
+    private int mLastDirection;
+
+    /**
+     * Creates a new injector associated with a given {@link WebViewClassic}.
+     *
+     * @param webView The associated WebViewClassic.
+     */
+    public AccessibilityInjectorFallback(WebViewClassic webView) {
+        mWebView = webView;
+        mWebViewInternal = mWebView.getWebView();
+        ensureWebContentKeyBindings();
+    }
+
+    /**
+     * Processes a key down <code>event</code>.
+     *
+     * @return True if the event was processed.
+     */
+    public boolean onKeyEvent(KeyEvent event) {
+        // We do not handle ENTER in any circumstances.
+        if (isEnterActionKey(event.getKeyCode())) {
+            return false;
+        }
+
+        if (event.getAction() == KeyEvent.ACTION_UP) {
+            return mLastDownEventHandled;
+        }
+
+        mLastDownEventHandled = false;
+
+        AccessibilityWebContentKeyBinding binding = null;
+        for (AccessibilityWebContentKeyBinding candidate : sBindings) {
+            if (event.getKeyCode() == candidate.getKeyCode()
+                    && event.hasModifiers(candidate.getModifiers())) {
+                binding = candidate;
+                break;
+            }
+        }
+
+        if (binding == null) {
+            return false;
+        }
+
+        for (int i = 0, count = binding.getActionCount(); i < count; i++) {
+            int actionCode = binding.getActionCode(i);
+            String contentDescription = Integer.toHexString(binding.getAction(i));
+            switch (actionCode) {
+                case ACTION_SET_CURRENT_AXIS:
+                    int axis = binding.getFirstArgument(i);
+                    boolean sendEvent = (binding.getSecondArgument(i) == 1);
+                    setCurrentAxis(axis, sendEvent, contentDescription);
+                    mLastDownEventHandled = true;
+                    break;
+                case ACTION_TRAVERSE_CURRENT_AXIS:
+                    int direction = binding.getFirstArgument(i);
+                    // on second null selection string in same direction - WebView handles the event
+                    if (direction == mLastDirection && mIsLastSelectionStringNull) {
+                        mIsLastSelectionStringNull = false;
+                        return false;
+                    }
+                    mLastDirection = direction;
+                    sendEvent = (binding.getSecondArgument(i) == 1);
+                    mLastDownEventHandled = traverseCurrentAxis(direction, sendEvent,
+                            contentDescription);
+                    break;
+                case ACTION_TRAVERSE_GIVEN_AXIS:
+                    direction = binding.getFirstArgument(i);
+                    // on second null selection string in same direction => WebView handle the event
+                    if (direction == mLastDirection && mIsLastSelectionStringNull) {
+                        mIsLastSelectionStringNull = false;
+                        return false;
+                    }
+                    mLastDirection = direction;
+                    axis =  binding.getSecondArgument(i);
+                    sendEvent = (binding.getThirdArgument(i) == 1);
+                    traverseGivenAxis(direction, axis, sendEvent, contentDescription);
+                    mLastDownEventHandled = true;
+                    break;
+                case ACTION_PERFORM_AXIS_TRANSITION:
+                    int fromAxis = binding.getFirstArgument(i);
+                    int toAxis = binding.getSecondArgument(i);
+                    sendEvent = (binding.getThirdArgument(i) == 1);
+                    performAxisTransition(fromAxis, toAxis, sendEvent, contentDescription);
+                    mLastDownEventHandled = true;
+                    break;
+                case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS:
+                    // This is a special case since we treat the default WebView navigation
+                    // behavior as one of the possible navigation axis the user can use.
+                    // If we are not on the default WebView navigation axis this is NOP.
+                    if (mCurrentAxis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+                        // While WebVew handles navigation we do not get null selection
+                        // strings so do not check for that here as the cases above.
+                        mLastDirection = binding.getFirstArgument(i);
+                        sendEvent = (binding.getSecondArgument(i) == 1);
+                        traverseGivenAxis(mLastDirection, NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR,
+                            sendEvent, contentDescription);
+                        mLastDownEventHandled = false;
+                    } else {
+                        mLastDownEventHandled = true;
+                    }
+                    break;
+                default:
+                    Log.w(LOG_TAG, "Unknown action code: " + actionCode);
+            }
+        }
+
+        return mLastDownEventHandled;
+    }
+
+    /**
+     * Set the current navigation axis which will be used while
+     * calling {@link #traverseCurrentAxis(int, boolean, String)}.
+     *
+     * @param axis The axis to set.
+     * @param sendEvent Whether to send an accessibility event to
+     *        announce the change.
+     */
+    private void setCurrentAxis(int axis, boolean sendEvent, String contentDescription) {
+        mCurrentAxis = axis;
+        if (sendEvent) {
+            final AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent(
+                    AccessibilityEvent.TYPE_ANNOUNCEMENT);
+            event.getText().add(String.valueOf(axis));
+            event.setContentDescription(contentDescription);
+            sendAccessibilityEvent(event);
+        }
+    }
+
+    /**
+     * Performs conditional transition one axis to another.
+     *
+     * @param fromAxis The axis which must be the current for the transition to occur.
+     * @param toAxis The axis to which to transition.
+     * @param sendEvent Flag if to send an event to announce successful transition.
+     * @param contentDescription A description of the performed action.
+     */
+    private void performAxisTransition(int fromAxis, int toAxis, boolean sendEvent,
+            String contentDescription) {
+        if (mCurrentAxis == fromAxis) {
+            setCurrentAxis(toAxis, sendEvent, contentDescription);
+        }
+    }
+
+    /**
+     * Traverse the document along the current navigation axis.
+     *
+     * @param direction The direction of traversal.
+     * @param sendEvent Whether to send an accessibility event to
+     *        announce the change.
+     * @param contentDescription A description of the performed action.
+     * @see #setCurrentAxis(int, boolean, String)
+     */
+    private boolean traverseCurrentAxis(int direction, boolean sendEvent,
+            String contentDescription) {
+        return traverseGivenAxis(direction, mCurrentAxis, sendEvent, contentDescription);
+    }
+    
+    boolean performAccessibilityAction(int action, Bundle arguments) {
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
+                final int direction = getDirectionForAction(action);
+                final int axis = getAxisForGranularity(arguments.getInt(
+                        AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT));
+                return traverseGivenAxis(direction, axis, true, null);
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Returns the {@link WebView}-defined direction for the given
+     * {@link AccessibilityNodeInfo}-defined action.
+     * 
+     * @param action An accessibility action identifier.
+     * @return A web view navigation direction.
+     */
+    private static int getDirectionForAction(int action) {
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+                return NAVIGATION_DIRECTION_FORWARD;
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
+                return NAVIGATION_DIRECTION_BACKWARD;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Returns the {@link WebView}-defined axis for the given
+     * {@link AccessibilityNodeInfo}-defined granularity.
+     * 
+     * @param granularity An accessibility granularity identifier.
+     * @return A web view navigation axis.
+     */
+    private static int getAxisForGranularity(int granularity) {
+        switch (granularity) {
+            case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER:
+                return NAVIGATION_AXIS_CHARACTER;
+            case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD:
+                return NAVIGATION_AXIS_WORD;
+            case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE:
+                return NAVIGATION_AXIS_SENTENCE;
+            case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH:
+                // TODO: Figure out what nextSibling() actually means.
+                return NAVIGATION_AXIS_SIBLING;
+            case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE:
+                return NAVIGATION_AXIS_DOCUMENT;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Traverse the document along the given navigation axis.
+     *
+     * @param direction The direction of traversal.
+     * @param axis The axis along which to traverse.
+     * @param sendEvent Whether to send an accessibility event to
+     *        announce the change.
+     * @param contentDescription A description of the performed action.
+     */
+    private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
+            String contentDescription) {
+        WebViewCore webViewCore = mWebView.getWebViewCore();
+        if (webViewCore == null) {
+            return false;
+        }
+
+        AccessibilityEvent event = null;
+        if (sendEvent) {
+            event = getPartialyPopulatedAccessibilityEvent(
+                    AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY);
+            // the text will be set upon receiving the selection string
+            event.setContentDescription(contentDescription);
+        }
+        mScheduledEventStack.push(event);
+
+        // if the axis is the default let WebView handle the event which will
+        // result in cursor ring movement and selection of its content
+        if (axis == NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR) {
+            return false;
+        }
+
+        webViewCore.sendMessage(EventHub.MODIFY_SELECTION, direction, axis);
+        return true;
+    }
+
+    /**
+     * Called when the <code>selectionString</code> has changed.
+     */
+    public void onSelectionStringChange(String selectionString) {
+        if (DEBUG) {
+            Log.d(LOG_TAG, "Selection string: " + selectionString);
+        }
+        mIsLastSelectionStringNull = (selectionString == null);
+        if (mScheduledEventStack.isEmpty()) {
+            return;
+        }
+        AccessibilityEvent event = mScheduledEventStack.pop();
+        if ((event != null) && (selectionString != null)) {
+            event.getText().add(selectionString);
+            event.setFromIndex(0);
+            event.setToIndex(selectionString.length());
+            sendAccessibilityEvent(event);
+        }
+    }
+
+    /**
+     * Sends an {@link AccessibilityEvent}.
+     *
+     * @param event The event to send.
+     */
+    private void sendAccessibilityEvent(AccessibilityEvent event) {
+        if (DEBUG) {
+            Log.d(LOG_TAG, "Dispatching: " + event);
+        }
+        // accessibility may be disabled while waiting for the selection string
+        AccessibilityManager accessibilityManager =
+            AccessibilityManager.getInstance(mWebView.getContext());
+        if (accessibilityManager.isEnabled()) {
+            accessibilityManager.sendAccessibilityEvent(event);
+        }
+    }
+
+    /**
+     * @return An accessibility event whose members are populated except its
+     *         text and content description.
+     */
+    private AccessibilityEvent getPartialyPopulatedAccessibilityEvent(int eventType) {
+        AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+        mWebViewInternal.onInitializeAccessibilityEvent(event);
+        return event;
+    }
+
+    /**
+     * Ensures that the Web content key bindings are loaded.
+     */
+    private void ensureWebContentKeyBindings() {
+        if (sBindings.size() > 0) {
+            return;
+        }
+
+        String webContentKeyBindingsString  = Settings.Secure.getString(
+                mWebView.getContext().getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
+
+        SimpleStringSplitter semiColonSplitter = new SimpleStringSplitter(';');
+        semiColonSplitter.setString(webContentKeyBindingsString);
+
+        while (semiColonSplitter.hasNext()) {
+            String bindingString = semiColonSplitter.next();
+            if (TextUtils.isEmpty(bindingString)) {
+                Log.e(LOG_TAG, "Disregarding malformed Web content key binding: "
+                        + webContentKeyBindingsString);
+                continue;
+            }
+            String[] keyValueArray = bindingString.split("=");
+            if (keyValueArray.length != 2) {
+                Log.e(LOG_TAG, "Disregarding malformed Web content key binding: " + bindingString);
+                continue;
+            }
+            try {
+                long keyCodeAndModifiers = Long.decode(keyValueArray[0].trim());
+                String[] actionStrings = keyValueArray[1].split(":");
+                int[] actions = new int[actionStrings.length];
+                for (int i = 0, count = actions.length; i < count; i++) {
+                    actions[i] = Integer.decode(actionStrings[i].trim());
+                }
+                sBindings.add(new AccessibilityWebContentKeyBinding(keyCodeAndModifiers, actions));
+            } catch (NumberFormatException nfe) {
+                Log.e(LOG_TAG, "Disregarding malformed key binding: " + bindingString);
+            }
+        }
+    }
+
+    private boolean isEnterActionKey(int keyCode) {
+        return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                || keyCode == KeyEvent.KEYCODE_ENTER
+                || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
+    }
+
+    /**
+     * Represents a web content key-binding.
+     */
+    private static final class AccessibilityWebContentKeyBinding {
+
+        private static final int MODIFIERS_OFFSET = 32;
+        private static final long MODIFIERS_MASK = 0xFFFFFFF00000000L;
+
+        private static final int KEY_CODE_OFFSET = 0;
+        private static final long KEY_CODE_MASK = 0x00000000FFFFFFFFL;
+
+        private static final int ACTION_OFFSET = 24;
+        private static final int ACTION_MASK = 0xFF000000;
+
+        private static final int FIRST_ARGUMENT_OFFSET = 16;
+        private static final int FIRST_ARGUMENT_MASK = 0x00FF0000;
+
+        private static final int SECOND_ARGUMENT_OFFSET = 8;
+        private static final int SECOND_ARGUMENT_MASK = 0x0000FF00;
+
+        private static final int THIRD_ARGUMENT_OFFSET = 0;
+        private static final int THIRD_ARGUMENT_MASK = 0x000000FF;
+
+        private final long mKeyCodeAndModifiers;
+
+        private final int [] mActionSequence;
+
+        /**
+         * @return The key code of the binding key.
+         */
+        public int getKeyCode() {
+            return (int) ((mKeyCodeAndModifiers & KEY_CODE_MASK) >> KEY_CODE_OFFSET);
+        }
+
+        /**
+         * @return The meta state of the binding key.
+         */
+        public int getModifiers() {
+            return (int) ((mKeyCodeAndModifiers & MODIFIERS_MASK) >> MODIFIERS_OFFSET);
+        }
+
+        /**
+         * @return The number of actions in the key binding.
+         */
+        public int getActionCount() {
+            return mActionSequence.length;
+        }
+
+        /**
+         * @param index The action for a given action <code>index</code>.
+         */
+        public int getAction(int index) {
+            return mActionSequence[index];
+        }
+
+        /**
+         * @param index The action code for a given action <code>index</code>.
+         */
+        public int getActionCode(int index) {
+            return (mActionSequence[index] & ACTION_MASK) >> ACTION_OFFSET;
+        }
+
+        /**
+         * @param index The first argument for a given action <code>index</code>.
+         */
+        public int getFirstArgument(int index) {
+            return (mActionSequence[index] & FIRST_ARGUMENT_MASK) >> FIRST_ARGUMENT_OFFSET;
+        }
+
+        /**
+         * @param index The second argument for a given action <code>index</code>.
+         */
+        public int getSecondArgument(int index) {
+            return (mActionSequence[index] & SECOND_ARGUMENT_MASK) >> SECOND_ARGUMENT_OFFSET;
+        }
+
+        /**
+         * @param index The third argument for a given action <code>index</code>.
+         */
+        public int getThirdArgument(int index) {
+            return (mActionSequence[index] & THIRD_ARGUMENT_MASK) >> THIRD_ARGUMENT_OFFSET;
+        }
+
+        /**
+         * Creates a new instance.
+         * @param keyCodeAndModifiers The key for the binding (key and modifiers).
+         * @param actionSequence The sequence of action for the binding.
+         */
+        public AccessibilityWebContentKeyBinding(long keyCodeAndModifiers, int[] actionSequence) {
+            mKeyCodeAndModifiers = keyCodeAndModifiers;
+            mActionSequence = actionSequence;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("modifiers: ");
+            builder.append(getModifiers());
+            builder.append(", keyCode: ");
+            builder.append(getKeyCode());
+            builder.append(", actions[");
+            for (int i = 0, count = getActionCount(); i < count; i++) {
+                builder.append("{actionCode");
+                builder.append(i);
+                builder.append(": ");
+                builder.append(getActionCode(i));
+                builder.append(", firstArgument: ");
+                builder.append(getFirstArgument(i));
+                builder.append(", secondArgument: ");
+                builder.append(getSecondArgument(i));
+                builder.append(", thirdArgument: ");
+                builder.append(getThirdArgument(i));
+                builder.append("}");
+            }
+            builder.append("]");
+            return builder.toString();
+        }
+    }
+}
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 6b7263c..1a4ccfa 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -34,7 +34,7 @@
 import android.widget.TextView;
 
 class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
-        View.OnLongClickListener, View.OnClickListener {
+        View.OnClickListener {
     private View mCustomView;
     private EditText mEditText;
     private TextView mMatches;
@@ -51,9 +51,7 @@
                 com.android.internal.R.layout.webview_find, null);
         mEditText = (EditText) mCustomView.findViewById(
                 com.android.internal.R.id.edit);
-        // Override long click so that select ActionMode is not opened, which
-        // would exit find ActionMode.
-        mEditText.setOnLongClickListener(this);
+        mEditText.setCustomSelectionActionModeCallback(new NoAction());
         mEditText.setOnClickListener(this);
         setText("");
         mMatches = (TextView) mCustomView.findViewById(
@@ -174,11 +172,6 @@
         mMatches.setVisibility(View.VISIBLE);
     }
 
-    // OnLongClickListener implementation
-
-    @Override
-    public boolean onLongClick(View v) { return true; }
-
     // OnClickListener implementation
 
     @Override
@@ -280,4 +273,24 @@
         return mGlobalVisibleRect.bottom;
     }
 
+    public static class NoAction implements ActionMode.Callback {
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return false;
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {
+        }
+    }
 }
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
index 689884f..fc5df2d 100644
--- a/core/java/android/webkit/HTML5Audio.java
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -67,6 +67,8 @@
 
     private String mUrl;
     private boolean mAskToPlay = false;
+    private boolean mLoopEnabled = false;
+    private boolean mProcessingOnEnd = false;
     private Context mContext;
 
     // Timer thread -> UI thread
@@ -143,7 +145,13 @@
     // MediaPlayer.OnCompletionListener;
     public void onCompletion(MediaPlayer mp) {
         mState = COMPLETE;
+        mProcessingOnEnd = true;
         nativeOnEnded(mNativePointer);
+        mProcessingOnEnd = false;
+        if (mLoopEnabled == true) {
+            nativeOnRequestPlay(mNativePointer);
+            mLoopEnabled = false;
+        }
     }
 
     // MediaPlayer.OnErrorListener
@@ -264,14 +272,10 @@
 
 
     private void play() {
-        if (mState == COMPLETE) {
+        if (mState == COMPLETE && mLoopEnabled == true) {
             // Play it again, Sam
-            mTimer.cancel();
-            mTimer = new Timer();
-            mAskToPlay = true;
-            mMediaPlayer.stop();
-            mState = STOPPED;
-            mMediaPlayer.prepareAsync();
+            mMediaPlayer.start();
+            mState = STARTED;
             return;
         }
 
@@ -304,14 +308,11 @@
     }
 
     private void seek(int msec) {
+        if (mProcessingOnEnd == true && mState == COMPLETE && msec == 0) {
+            mLoopEnabled = true;
+        }
         if (mState >= PREPARED) {
             mMediaPlayer.seekTo(msec);
-            if (mState == COMPLETE) {
-                // Seeking after the stream had completed will
-                // cause us to start playing again. This is to
-                // support audio tags that specify loop=true.
-                play();
-            }
         }
     }
 
@@ -336,6 +337,7 @@
 
     private native void nativeOnBuffering(int percent, int nativePointer);
     private native void nativeOnEnded(int nativePointer);
+    private native void nativeOnRequestPlay(int nativePointer);
     private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
     private native void nativeOnTimeupdate(int position, int nativePointer);
 
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index 57628d3..f9f5b03 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.app.Activity;
 import android.app.SearchManager;
 import android.content.ClipboardManager;
 import android.content.Context;
@@ -122,6 +123,9 @@
                 Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
                 i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
                 i.putExtra(SearchManager.QUERY, mWebView.getSelection());
+                if (!(mWebView.getContext() instanceof Activity)) {
+                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                }
                 mWebView.getContext().startActivity(i);
                 break;
 
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index 655db31..a22e6e8 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -26,6 +26,10 @@
 import android.os.Process;
 import android.webkit.WebViewCore.EventHub;
 
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
 // A Runnable that will monitor if the WebCore thread is still
 // processing messages by pinging it every so often. It is safe
 // to call the public methods of this class from any thread.
@@ -51,25 +55,31 @@
     // After the first timeout, use a shorter period before re-prompting the user.
     private static final int SUBSEQUENT_TIMEOUT_PERIOD = 15 * 1000;
 
-    private Context mContext;
     private Handler mWebCoreThreadHandler;
     private Handler mHandler;
     private boolean mPaused;
 
+    private Set<WebViewClassic> mWebViews;
+
     private static WebCoreThreadWatchdog sInstance;
 
-    public synchronized static WebCoreThreadWatchdog start(Context context,
-            Handler webCoreThreadHandler) {
+    public synchronized static WebCoreThreadWatchdog start(Handler webCoreThreadHandler) {
         if (sInstance == null) {
-            sInstance = new WebCoreThreadWatchdog(context, webCoreThreadHandler);
+            sInstance = new WebCoreThreadWatchdog(webCoreThreadHandler);
             new Thread(sInstance, "WebCoreThreadWatchdog").start();
         }
         return sInstance;
     }
 
-    public synchronized static void updateContext(Context context) {
+    public synchronized static void registerWebView(WebViewClassic w) {
         if (sInstance != null) {
-            sInstance.setContext(context);
+            sInstance.addWebView(w);
+        }
+    }
+
+    public synchronized static void unregisterWebView(WebViewClassic w) {
+        if (sInstance != null) {
+            sInstance.removeWebView(w);
         }
     }
 
@@ -85,12 +95,18 @@
         }
     }
 
-    private void setContext(Context context) {
-        mContext = context;
+    private void addWebView(WebViewClassic w) {
+        if (mWebViews == null) {
+            mWebViews = new HashSet<WebViewClassic>();
+        }
+        mWebViews.add(w);
     }
 
-    private WebCoreThreadWatchdog(Context context, Handler webCoreThreadHandler) {
-        mContext = context;
+    private void removeWebView(WebViewClassic w) {
+        mWebViews.remove(w);
+    }
+
+    private WebCoreThreadWatchdog(Handler webCoreThreadHandler) {
         mWebCoreThreadHandler = webCoreThreadHandler;
     }
 
@@ -147,39 +163,41 @@
                         break;
 
                     case TIMED_OUT:
-                        if ((mContext == null) || !(mContext instanceof Activity)) return;
-                        new AlertDialog.Builder(mContext)
-                            .setMessage(com.android.internal.R.string.webpage_unresponsive)
-                            .setPositiveButton(com.android.internal.R.string.force_close,
-                                    new DialogInterface.OnClickListener() {
-                                        @Override
-                                        public void onClick(DialogInterface dialog, int which) {
-                                        // User chose to force close.
-                                        Process.killProcess(Process.myPid());
+                        boolean postedDialog = false;
+                        synchronized (WebCoreThreadWatchdog.class) {
+                            Iterator<WebViewClassic> it = mWebViews.iterator();
+                            // Check each WebView we are aware of and find one that is capable of
+                            // showing the user a prompt dialog.
+                            while (it.hasNext()) {
+                                WebView activeView = it.next().getWebView();
+
+                                if (activeView.getWindowToken() != null &&
+                                        activeView.getViewRootImpl() != null) {
+                                    postedDialog = activeView.post(new PageNotRespondingRunnable(
+                                            activeView.getContext(), this));
+
+                                    if (postedDialog) {
+                                        // We placed the message into the UI thread for an attached
+                                        // WebView so we've made our best attempt to display the
+                                        // "page not responding" dialog to the user. Although the
+                                        // message is in the queue, there is no guarantee when/if
+                                        // the runnable will execute. In the case that the runnable
+                                        // never executes, the user will need to terminate the
+                                        // process manually.
+                                        break;
                                     }
-                                })
-                            .setNegativeButton(com.android.internal.R.string.wait,
-                                    new DialogInterface.OnClickListener() {
-                                        @Override
-                                        public void onClick(DialogInterface dialog, int which) {
-                                            // The user chose to wait. The last HEARTBEAT message
-                                            // will still be in the WebCore thread's queue, so all
-                                            // we need to do is post another TIMED_OUT so that the
-                                            // user will get prompted again if the WebCore thread
-                                            // doesn't sort itself out.
-                                            sendMessageDelayed(obtainMessage(TIMED_OUT),
-                                                    SUBSEQUENT_TIMEOUT_PERIOD);
-                                       }
-                                    })
-                            .setOnCancelListener(new DialogInterface.OnCancelListener() {
-                                    @Override
-                                    public void onCancel(DialogInterface dialog) {
-                                        sendMessageDelayed(obtainMessage(TIMED_OUT),
-                                                SUBSEQUENT_TIMEOUT_PERIOD);
-                                    }
-                            })
-                            .setIcon(android.R.drawable.ic_dialog_alert)
-                            .show();
+                                }
+                            }
+
+                            if (!postedDialog) {
+                                // There's no active webview we can use to show the dialog, so
+                                // wait again. If we never get a usable view, the user will
+                                // never get the chance to terminate the process, and will
+                                // need to do it manually.
+                                sendMessageDelayed(obtainMessage(TIMED_OUT),
+                                        SUBSEQUENT_TIMEOUT_PERIOD);
+                            }
+                        }
                         break;
                     }
                 }
@@ -205,4 +223,55 @@
 
         Looper.loop();
     }
+
+    private class PageNotRespondingRunnable implements Runnable {
+        Context mContext;
+        private Handler mWatchdogHandler;
+
+        public PageNotRespondingRunnable(Context context, Handler watchdogHandler) {
+            mContext = context;
+            mWatchdogHandler = watchdogHandler;
+        }
+
+        @Override
+        public void run() {
+            // This must run on the UI thread as it is displaying an AlertDialog.
+            assert Looper.getMainLooper().getThread() == Thread.currentThread();
+            new AlertDialog.Builder(mContext)
+                    .setMessage(com.android.internal.R.string.webpage_unresponsive)
+                    .setPositiveButton(com.android.internal.R.string.force_close,
+                            new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    // User chose to force close.
+                                    Process.killProcess(Process.myPid());
+                                }
+                            })
+                    .setNegativeButton(com.android.internal.R.string.wait,
+                            new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    // The user chose to wait. The last HEARTBEAT message
+                                    // will still be in the WebCore thread's queue, so all
+                                    // we need to do is post another TIMED_OUT so that the
+                                    // user will get prompted again if the WebCore thread
+                                    // doesn't sort itself out.
+                                    mWatchdogHandler.sendMessageDelayed(
+                                            mWatchdogHandler.obtainMessage(TIMED_OUT),
+                                            SUBSEQUENT_TIMEOUT_PERIOD);
+                                }
+                            })
+                    .setOnCancelListener(
+                            new DialogInterface.OnCancelListener() {
+                                @Override
+                                public void onCancel(DialogInterface dialog) {
+                                    mWatchdogHandler.sendMessageDelayed(
+                                            mWatchdogHandler.obtainMessage(TIMED_OUT),
+                                            SUBSEQUENT_TIMEOUT_PERIOD);
+                                }
+                            })
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .show();
+        }
+    }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ba5a417..cbb3011 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1686,6 +1686,10 @@
             WebView.super.computeScroll();
         }
 
+        public boolean super_performAccessibilityAction(int action, Bundle arguments) {
+            return WebView.super.performAccessibilityAction(action, arguments);
+        }
+
         public boolean super_performLongClick() {
             return WebView.super.performLongClick();
         }
@@ -1938,6 +1942,11 @@
         mProvider.getViewDelegate().onInitializeAccessibilityEvent(event);
     }
 
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        return mProvider.getViewDelegate().performAccessibilityAction(action, arguments);
+    }
+
     /** @hide */
     @Override
     protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar,
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index f1f3db2..65fd59a 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -60,9 +60,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.security.KeyChain;
-import android.speech.tts.TextToSpeech;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
@@ -102,7 +100,6 @@
 import android.webkit.WebViewCore.EventHub;
 import android.webkit.WebViewCore.TextFieldInitData;
 import android.webkit.WebViewCore.TextSelectionData;
-import android.webkit.WebViewCore.TouchHighlightData;
 import android.webkit.WebViewCore.WebKitHitTest;
 import android.widget.AbsoluteLayout;
 import android.widget.Adapter;
@@ -276,6 +273,7 @@
                 newCursorPosition -= text.length() - limitedText.length();
             }
             super.setComposingText(limitedText, newCursorPosition);
+            updateSelection();
             if (limitedText != text) {
                 restartInput();
                 int lastCaret = start + limitedText.length();
@@ -288,19 +286,44 @@
         @Override
         public boolean commitText(CharSequence text, int newCursorPosition) {
             setComposingText(text, newCursorPosition);
-            int cursorPosition = Selection.getSelectionEnd(getEditable());
-            setComposingRegion(cursorPosition, cursorPosition);
+            finishComposingText();
             return true;
         }
 
         @Override
         public boolean deleteSurroundingText(int leftLength, int rightLength) {
-            Editable editable = getEditable();
-            int cursorPosition = Selection.getSelectionEnd(editable);
-            int startDelete = Math.max(0, cursorPosition - leftLength);
-            int endDelete = Math.min(editable.length(),
-                    cursorPosition + rightLength);
-            setNewText(startDelete, endDelete, "");
+            // This code is from BaseInputConnection#deleteSurroundText.
+            // We have to delete the same text in webkit.
+            Editable content = getEditable();
+            int a = Selection.getSelectionStart(content);
+            int b = Selection.getSelectionEnd(content);
+
+            if (a > b) {
+                int tmp = a;
+                a = b;
+                b = tmp;
+            }
+
+            int ca = getComposingSpanStart(content);
+            int cb = getComposingSpanEnd(content);
+            if (cb < ca) {
+                int tmp = ca;
+                ca = cb;
+                cb = tmp;
+            }
+            if (ca != -1 && cb != -1) {
+                if (ca < a) a = ca;
+                if (cb > b) b = cb;
+            }
+
+            int endDelete = Math.min(content.length(), b + rightLength);
+            if (endDelete > b) {
+                setNewText(b, endDelete, "");
+            }
+            int startDelete = Math.max(0, a - leftLength);
+            if (startDelete < a) {
+                setNewText(startDelete, a, "");
+            }
             return super.deleteSurroundingText(leftLength, rightLength);
         }
 
@@ -413,6 +436,46 @@
             outAttrs.imeOptions = mImeOptions;
             outAttrs.hintText = mHint;
             outAttrs.initialCapsMode = getCursorCapsMode(InputType.TYPE_CLASS_TEXT);
+
+            Editable editable = getEditable();
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            if (selectionStart < 0 || selectionEnd < 0) {
+                selectionStart = editable.length();
+                selectionEnd = selectionStart;
+            }
+            outAttrs.initialSelStart = selectionStart;
+            outAttrs.initialSelEnd = selectionEnd;
+        }
+
+        @Override
+        public boolean setSelection(int start, int end) {
+            boolean result = super.setSelection(start, end);
+            updateSelection();
+            return result;
+        }
+
+        @Override
+        public boolean setComposingRegion(int start, int end) {
+            boolean result = super.setComposingRegion(start, end);
+            updateSelection();
+            return result;
+        }
+
+        /**
+         * Send the selection and composing spans to the IME.
+         */
+        private void updateSelection() {
+            Editable editable = getEditable();
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            int composingStart = getComposingSpanStart(editable);
+            int composingEnd = getComposingSpanEnd(editable);
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) {
+                imm.updateSelection(mWebView, selectionStart, selectionEnd,
+                        composingStart, composingEnd);
+            }
         }
 
         /**
@@ -431,14 +494,18 @@
             boolean isCharacterDelete = false;
             int textLength = text.length();
             int originalLength = original.length();
-            if (textLength > originalLength) {
-                isCharacterAdd = (textLength == originalLength + 1)
-                        && TextUtils.regionMatches(text, 0, original, 0,
-                                originalLength);
-            } else if (originalLength > textLength) {
-                isCharacterDelete = (textLength == originalLength - 1)
-                        && TextUtils.regionMatches(text, 0, original, 0,
-                                textLength);
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            if (selectionStart == selectionEnd) {
+                if (textLength > originalLength) {
+                    isCharacterAdd = (textLength == originalLength + 1)
+                            && TextUtils.regionMatches(text, 0, original, 0,
+                                    originalLength);
+                } else if (originalLength > textLength) {
+                    isCharacterDelete = (textLength == originalLength - 1)
+                            && TextUtils.regionMatches(text, 0, original, 0,
+                                    textLength);
+                }
             }
             if (isCharacterAdd) {
                 sendCharacter(text.charAt(textLength - 1));
@@ -867,15 +934,9 @@
     private static final int MOTIONLESS_IGNORE          = 3;
     private int mHeldMotionless;
 
-    // An instance for injecting accessibility in WebViews with disabled
-    // JavaScript or ones for which no accessibility script exists
+    // Lazily-instantiated instance for injecting accessibility.
     private AccessibilityInjector mAccessibilityInjector;
 
-    // flag indicating if accessibility script is injected so we
-    // know to handle Shift and arrows natively first
-    private boolean mAccessibilityScriptInjected;
-
-
     /**
      * How long the caret handle will last without being touched.
      */
@@ -934,7 +995,6 @@
     private static final int RELEASE_SINGLE_TAP         = 5;
     private static final int REQUEST_FORM_DATA          = 6;
     private static final int DRAG_HELD_MOTIONLESS       = 8;
-    private static final int AWAKEN_SCROLL_BARS         = 9;
     private static final int PREVENT_DEFAULT_TIMEOUT    = 10;
     private static final int SCROLL_SELECT_TEXT         = 11;
 
@@ -1002,7 +1062,7 @@
         "REQUEST_FORM_DATA", //              = 6;
         "RESUME_WEBCORE_PRIORITY", //        = 7;
         "DRAG_HELD_MOTIONLESS", //           = 8;
-        "AWAKEN_SCROLL_BARS", //             = 9;
+        "", //             = 9;
         "PREVENT_DEFAULT_TIMEOUT", //        = 10;
         "SCROLL_SELECT_TEXT" //              = 11;
     };
@@ -1085,34 +1145,6 @@
     private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
     private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
 
-    // constants for determining script injection strategy
-    private static final int ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED = -1;
-    private static final int ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT = 0;
-    private static final int ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED = 1;
-
-    // the alias via which accessibility JavaScript interface is exposed
-    private static final String ALIAS_ACCESSIBILITY_JS_INTERFACE = "accessibility";
-
-    // Template for JavaScript that injects a screen-reader.
-    private static final String ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE =
-        "javascript:(function() {" +
-        "    var chooser = document.createElement('script');" +
-        "    chooser.type = 'text/javascript';" +
-        "    chooser.src = '%1s';" +
-        "    document.getElementsByTagName('head')[0].appendChild(chooser);" +
-        "  })();";
-
-    // Regular expression that matches the "axs" URL parameter.
-    // The value of 0 means the accessibility script is opted out
-    // The value of 1 means the accessibility script is already injected
-    private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))";
-
-    // TextToSpeech instance exposed to JavaScript to the injected screenreader.
-    private TextToSpeech mTextToSpeech;
-
-    // variable to cache the above pattern in case accessibility is enabled.
-    private Pattern mMatchAxsUrlParameterPattern;
-
     /**
      * Max distance to overscroll by in pixels.
      * This how far content can be pulled beyond its normal bounds by the user.
@@ -1598,8 +1630,6 @@
     private void init() {
         OnTrimMemoryListener.init(mContext);
         mWebView.setWillNotDraw(false);
-        mWebView.setFocusable(true);
-        mWebView.setFocusableInTouchMode(true);
         mWebView.setClickable(true);
         mWebView.setLongClickable(true);
 
@@ -1633,43 +1663,66 @@
         return true;
     }
 
-    /**
-     * Adds accessibility APIs to JavaScript.
-     *
-     * Note: This method is responsible to performing the necessary
-     *       check if the accessibility APIs should be exposed.
-     */
-    private void addAccessibilityApisToJavaScript() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()
-                && getSettings().getJavaScriptEnabled()) {
-            // exposing the TTS for now ...
-            final Context ctx = mContext;
-            if (ctx != null) {
-                final String packageName = ctx.getPackageName();
-                if (packageName != null) {
-                    mTextToSpeech = new TextToSpeech(ctx, null, null,
-                            packageName + ".**webview**", true);
-                    addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (!mWebView.isEnabled()) {
+            // Only default actions are supported while disabled.
+            return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
+        }
+
+        if (getAccessibilityInjector().supportsAccessibilityAction(action)) {
+            return getAccessibilityInjector().performAccessibilityAction(action, arguments);
+        }
+
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                final int convertedContentHeight = contentToViewY(getContentHeight());
+                final int adjustedViewHeight = getHeight() - mWebView.getPaddingTop()
+                        - mWebView.getPaddingBottom();
+                final int maxScrollY = Math.max(convertedContentHeight - adjustedViewHeight, 0);
+                final boolean canScrollBackward = (getScrollY() > 0);
+                final boolean canScrollForward = ((getScrollY() - maxScrollY) > 0);
+                if ((action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) && canScrollBackward) {
+                    mWebView.scrollBy(0, adjustedViewHeight);
+                    return true;
                 }
+                if ((action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) && canScrollForward) {
+                    mWebView.scrollBy(0, -adjustedViewHeight);
+                    return true;
+                }
+                return false;
             }
         }
-    }
 
-    /**
-     * Removes accessibility APIs from JavaScript.
-     */
-    private void removeAccessibilityApisFromJavaScript() {
-        // exposing the TTS for now ...
-        if (mTextToSpeech != null) {
-            removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
-            mTextToSpeech.shutdown();
-            mTextToSpeech = null;
-        }
+        return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        if (!mWebView.isEnabled()) {
+            // Only default actions are supported while disabled.
+            return;
+        }
+
         info.setScrollable(isScrollableForAccessibility());
+
+        final int convertedContentHeight = contentToViewY(getContentHeight());
+        final int adjustedViewHeight = getHeight() - mWebView.getPaddingTop()
+                - mWebView.getPaddingBottom();
+        final int maxScrollY = Math.max(convertedContentHeight - adjustedViewHeight, 0);
+        final boolean canScrollBackward = (getScrollY() > 0);
+        final boolean canScrollForward = ((getScrollY() - maxScrollY) > 0);
+
+        if (canScrollForward) {
+            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+        }
+
+        if (canScrollForward) {
+            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+        }
+
+        getAccessibilityInjector().onInitializeAccessibilityNodeInfo(info);
     }
 
     @Override
@@ -1687,6 +1740,17 @@
         event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
     }
 
+    private boolean isAccessibilityEnabled() {
+        return AccessibilityManager.getInstance(mContext).isEnabled();
+    }
+
+    private AccessibilityInjector getAccessibilityInjector() {
+        if (mAccessibilityInjector == null) {
+            mAccessibilityInjector = new AccessibilityInjector(this);
+        }
+        return mAccessibilityInjector;
+    }
+
     private boolean isScrollableForAccessibility() {
         return (contentToViewX(getContentWidth()) > getWidth() - mWebView.getPaddingLeft()
                 - mWebView.getPaddingRight()
@@ -2005,6 +2069,20 @@
     }
 
     private void destroyImpl() {
+        ViewRootImpl viewRoot = mWebView.getViewRootImpl();
+        if (viewRoot != null) {
+            Log.e(LOGTAG, "Error: WebView.destroy() called while still attached!");
+        }
+
+        if (mWebView.isHardwareAccelerated()) {
+            int drawGLFunction = nativeGetDrawGLFunction(mNativeClass);
+            if (drawGLFunction != 0 && viewRoot != null) {
+                // functor should have been detached in onDetachedFromWindow, do
+                // additionally here for safety
+                viewRoot.detachFunctor(drawGLFunction);
+            }
+        }
+
         mCallbackProxy.blockMessages();
         clearHelpers();
         if (mListBoxDialog != null) {
@@ -3368,11 +3446,6 @@
                 nativeSetPauseDrawing(mNativeClass, false);
             }
         }
-        // Ensure that the watchdog has a currently valid Context to be able to display
-        // a prompt dialog. For example, if the Activity was finished whilst the WebCore
-        // thread was blocked and the Activity is started again, we may reuse the blocked
-        // thread, but we'll have a new Activity.
-        WebCoreThreadWatchdog.updateContext(mContext);
         // We get a call to onResume for new WebViews (i.e. mIsPaused will be false). We need
         // to ensure that the Watchdog thread is running for the new WebView, so call
         // it outside the if block above.
@@ -3775,7 +3848,6 @@
             //        Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
             mScroller.startScroll(getScrollX(), getScrollY(), dx, dy,
                     animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
-            mWebViewPrivate.awakenScrollBars(mScroller.getDuration());
             invalidate();
         } else {
             mWebView.scrollTo(x, y);
@@ -3828,7 +3900,9 @@
 
         // reset the flag since we set to true in if need after
         // loading is see onPageFinished(Url)
-        mAccessibilityScriptInjected = false;
+        if (isAccessibilityEnabled()) {
+            getAccessibilityInjector().onPageStarted(url);
+        }
 
         // Don't start out editing.
         mIsEditingText = false;
@@ -3840,114 +3914,10 @@
      */
     /* package */ void onPageFinished(String url) {
         mZoomManager.onPageFinished(url);
-        injectAccessibilityForUrl(url);
-    }
 
-    /**
-     * This method injects accessibility in the loaded document if accessibility
-     * is enabled. If JavaScript is enabled we try to inject a URL specific script.
-     * If no URL specific script is found or JavaScript is disabled we fallback to
-     * the default {@link AccessibilityInjector} implementation.
-     * </p>
-     * If the URL has the "axs" paramter set to 1 it has already done the
-     * script injection so we do nothing. If the parameter is set to 0
-     * the URL opts out accessibility script injection so we fall back to
-     * the default {@link AccessibilityInjector}.
-     * </p>
-     * Note: If the user has not opted-in the accessibility script injection no scripts
-     * are injected rather the default {@link AccessibilityInjector} implementation
-     * is used.
-     *
-     * @param url The URL loaded by this {@link WebView}.
-     */
-    private void injectAccessibilityForUrl(String url) {
-        if (mWebViewCore == null) {
-            return;
+        if (isAccessibilityEnabled()) {
+            getAccessibilityInjector().onPageFinished(url);
         }
-        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
-
-        if (!accessibilityManager.isEnabled()) {
-            // it is possible that accessibility was turned off between reloads
-            ensureAccessibilityScriptInjectorInstance(false);
-            return;
-        }
-
-        if (!getSettings().getJavaScriptEnabled()) {
-            // no JS so we fallback to the basic buil-in support
-            ensureAccessibilityScriptInjectorInstance(true);
-            return;
-        }
-
-        // check the URL "axs" parameter to choose appropriate action
-        int axsParameterValue = getAxsUrlParameterValue(url);
-        if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
-            boolean onDeviceScriptInjectionEnabled = (Settings.Secure.getInt(mContext
-                    .getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
-            if (onDeviceScriptInjectionEnabled) {
-                ensureAccessibilityScriptInjectorInstance(false);
-                // neither script injected nor script injection opted out => we inject
-                mWebView.loadUrl(getScreenReaderInjectingJs());
-                // TODO: Set this flag after successfull script injection. Maybe upon injection
-                // the chooser should update the meta tag and we check it to declare success
-                mAccessibilityScriptInjected = true;
-            } else {
-                // injection disabled so we fallback to the basic built-in support
-                ensureAccessibilityScriptInjectorInstance(true);
-            }
-        } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_OPTED_OUT) {
-            // injection opted out so we fallback to the basic buil-in support
-            ensureAccessibilityScriptInjectorInstance(true);
-        } else if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_PROVIDED) {
-            ensureAccessibilityScriptInjectorInstance(false);
-            // the URL provides accessibility but we still need to add our generic script
-            mWebView.loadUrl(getScreenReaderInjectingJs());
-        } else {
-            Log.e(LOGTAG, "Unknown URL value for the \"axs\" URL parameter: " + axsParameterValue);
-        }
-    }
-
-    /**
-     * Ensures the instance of the {@link AccessibilityInjector} to be present ot not.
-     *
-     * @param present True to ensure an insance, false to ensure no instance.
-     */
-    private void ensureAccessibilityScriptInjectorInstance(boolean present) {
-        if (present) {
-            if (mAccessibilityInjector == null) {
-                mAccessibilityInjector = new AccessibilityInjector(this);
-            }
-        } else {
-            mAccessibilityInjector = null;
-        }
-    }
-
-    /**
-     * Gets JavaScript that injects a screen-reader.
-     *
-     * @return The JavaScript snippet.
-     */
-    private String getScreenReaderInjectingJs() {
-        String screenReaderUrl = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL);
-        return String.format(ACCESSIBILITY_SCREEN_READER_JAVASCRIPT_TEMPLATE, screenReaderUrl);
-    }
-
-    /**
-     * Gets the "axs" URL parameter value.
-     *
-     * @param url A url to fetch the paramter from.
-     * @return The parameter value if such, -1 otherwise.
-     */
-    private int getAxsUrlParameterValue(String url) {
-        if (mMatchAxsUrlParameterPattern == null) {
-            mMatchAxsUrlParameterPattern = Pattern.compile(PATTERN_MATCH_AXS_URL_PARAMETER);
-        }
-        Matcher matcher = mMatchAxsUrlParameterPattern.matcher(url);
-        if (matcher.find()) {
-            String keyValuePair = url.substring(matcher.start(), matcher.end());
-            return Integer.parseInt(keyValuePair.split("=")[1]);
-        }
-        return -1;
     }
 
     // scale from content to view coordinates, and pin
@@ -4158,15 +4128,11 @@
         if (mTouchMode == TOUCH_DRAG_MODE) {
             if (mHeldMotionless == MOTIONLESS_PENDING) {
                 mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
-                mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
                 mHeldMotionless = MOTIONLESS_FALSE;
             }
             if (mHeldMotionless == MOTIONLESS_FALSE) {
                 mPrivateHandler.sendMessageDelayed(mPrivateHandler
                         .obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
-                mPrivateHandler.sendMessageDelayed(mPrivateHandler
-                        .obtainMessage(AWAKEN_SCROLL_BARS),
-                            ViewConfiguration.getScrollDefaultDelay());
                 mHeldMotionless = MOTIONLESS_PENDING;
             }
         }
@@ -4437,8 +4403,11 @@
         if (mNativeClass == 0)
             return;
         boolean queueFull;
+        final int scrollingLayer = (mTouchMode == TOUCH_DRAG_LAYER_MODE)
+                ? mCurrentScrollingLayerId : 0;
         queueFull = nativeSetBaseLayer(mNativeClass, layer,
-                                       showVisualIndicator, isPictureAfterFirstLayout);
+                                       showVisualIndicator, isPictureAfterFirstLayout,
+                                       scrollingLayer);
 
         if (queueFull) {
             mWebViewCore.pauseWebKitDraw();
@@ -4909,30 +4878,10 @@
             return false;
         }
 
-        // accessibility support
-        if (accessibilityScriptInjected()) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                // if an accessibility script is injected we delegate to it the key handling.
-                // this script is a screen reader which is a fully fledged solution for blind
-                // users to navigate in and interact with web pages.
-                sendBatchableInputMessage(EventHub.KEY_DOWN, 0, 0, event);
-                return true;
-            } else {
-                // Clean up if accessibility was disabled after loading the current URL.
-                mAccessibilityScriptInjected = false;
-            }
-        } else if (mAccessibilityInjector != null) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                if (mAccessibilityInjector.onKeyEvent(event)) {
-                    // if an accessibility injector is present (no JavaScript enabled or the site
-                    // opts out injecting our JavaScript screen reader) we let it decide whether
-                    // to act on and consume the event.
-                    return true;
-                }
-            } else {
-                // Clean up if accessibility was disabled after loading the current URL.
-                mAccessibilityInjector = null;
-            }
+        // See if the accessibility injector needs to handle this event.
+        if (isAccessibilityEnabled()
+                && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
+            return true;
         }
 
         if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
@@ -5036,30 +4985,10 @@
             return false;
         }
 
-        // accessibility support
-        if (accessibilityScriptInjected()) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                // if an accessibility script is injected we delegate to it the key handling.
-                // this script is a screen reader which is a fully fledged solution for blind
-                // users to navigate in and interact with web pages.
-                sendBatchableInputMessage(EventHub.KEY_UP, 0, 0, event);
-                return true;
-            } else {
-                // Clean up if accessibility was disabled after loading the current URL.
-                mAccessibilityScriptInjected = false;
-            }
-        } else if (mAccessibilityInjector != null) {
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                if (mAccessibilityInjector.onKeyEvent(event)) {
-                    // if an accessibility injector is present (no JavaScript enabled or the site
-                    // opts out injecting our JavaScript screen reader) we let it decide whether to
-                    // act on and consume the event.
-                    return true;
-                }
-            } else {
-                // Clean up if accessibility was disabled after loading the current URL.
-                mAccessibilityInjector = null;
-            }
+        // See if the accessibility injector needs to handle this event.
+        if (isAccessibilityEnabled()
+                && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
+            return true;
         }
 
         if (isEnterActionKey(keyCode)) {
@@ -5175,6 +5104,7 @@
 
     private void adjustSelectionCursors() {
         if (mIsCaretSelection) {
+            syncSelectionCursors();
             return; // no need to swap left and right handles.
         }
 
@@ -5360,7 +5290,9 @@
     public void onAttachedToWindow() {
         if (mWebView.hasWindowFocus()) setActive(true);
 
-        addAccessibilityApisToJavaScript();
+        if (isAccessibilityEnabled()) {
+            getAccessibilityInjector().addAccessibilityApisIfNecessary();
+        }
 
         updateHwAccelerated();
     }
@@ -5371,7 +5303,14 @@
         mZoomManager.dismissZoomPicker();
         if (mWebView.hasWindowFocus()) setActive(false);
 
-        removeAccessibilityApisFromJavaScript();
+        if (isAccessibilityEnabled()) {
+            getAccessibilityInjector().removeAccessibilityApisIfNecessary();
+        } else {
+            // Ensure the injector is cleared if we're detaching from the window
+            // and accessibility is disabled.
+            mAccessibilityInjector = null;
+        }
+
         updateHwAccelerated();
 
         if (mWebView.isHardwareAccelerated()) {
@@ -5583,6 +5522,7 @@
             return; // no need to scroll
         }
         syncSelectionCursors();
+        nativeFindMaxVisibleRect(mNativeClass, mEditTextLayerId, visibleRect);
         final int buffer = Math.max(1, viewToContentDimension(EDIT_RECT_BUFFER));
         Rect showRect = new Rect(
                 Math.max(0, mEditTextContentBounds.left - buffer),
@@ -5615,17 +5555,19 @@
             return; // no need to scroll
         }
 
-        int scrollX = visibleRect.left;
+        int scrollX = viewToContentX(getScrollX());
         if (visibleRect.left > showRect.left) {
-            scrollX = showRect.left;
+            // We are scrolled too far
+            scrollX += showRect.left - visibleRect.left;
         } else if (visibleRect.right < showRect.right) {
-            scrollX = Math.max(0, showRect.right - visibleRect.width());
+            // We aren't scrolled enough to include the right
+            scrollX += showRect.right - visibleRect.right;
         }
-        int scrollY = visibleRect.top;
+        int scrollY = viewToContentY(getScrollY());
         if (visibleRect.top > showRect.top) {
-            scrollY = showRect.top;
+            scrollY += showRect.top - visibleRect.top;
         } else if (visibleRect.bottom < showRect.bottom) {
-            scrollY = Math.max(0, showRect.bottom - visibleRect.height());
+            scrollY += showRect.bottom - visibleRect.bottom;
         }
 
         contentScrollTo(scrollX, scrollY, false);
@@ -5767,14 +5709,15 @@
             return false;
         }
 
-        if (!mWebView.isFocused()) {
-            mWebView.requestFocus();
-        }
-
         if (mInputDispatcher == null) {
             return false;
         }
 
+        if (mWebView.isFocusable() && mWebView.isFocusableInTouchMode()
+                && !mWebView.isFocused()) {
+            mWebView.requestFocus();
+        }
+
         if (mInputDispatcher.postPointerEvent(ev, getScrollX(),
                 getScrollY() - getTitleHeight(), mZoomManager.getInvScale())) {
             mInputDispatcher.dispatchUiEvents();
@@ -6048,27 +5991,6 @@
                     }
                 }
 
-                // Turn off scrollbars when dragging a layer.
-                if (keepScrollBarsVisible &&
-                        mTouchMode != TOUCH_DRAG_LAYER_MODE &&
-                        mTouchMode != TOUCH_DRAG_TEXT_MODE) {
-                    if (mHeldMotionless != MOTIONLESS_TRUE) {
-                        mHeldMotionless = MOTIONLESS_TRUE;
-                        invalidate();
-                    }
-                    // keep the scrollbar on the screen even there is no scroll
-                    mWebViewPrivate.awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
-                            false);
-                    // Post a message so that we'll keep them alive while we're not scrolling.
-                    mPrivateHandler.sendMessageDelayed(mPrivateHandler
-                            .obtainMessage(AWAKEN_SCROLL_BARS),
-                            ViewConfiguration.getScrollDefaultDelay());
-                    // return false to indicate that we can't pan out of the
-                    // view space
-                    return;
-                } else {
-                    mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
-                }
                 break;
             }
             case MotionEvent.ACTION_UP: {
@@ -6116,7 +6038,6 @@
                     case TOUCH_DRAG_LAYER_MODE:
                     case TOUCH_DRAG_TEXT_MODE:
                         mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
-                        mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
                         // if the user waits a while w/o moving before the
                         // up, we don't want to do a fling
                         if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
@@ -6382,7 +6303,6 @@
         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
         mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
-        mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
         removeTouchHighlight();
         mHeldMotionless = MOTIONLESS_TRUE;
         mTouchMode = TOUCH_DONE_MODE;
@@ -6814,17 +6734,6 @@
         // no horizontal overscroll if the content just fits
         mScroller.fling(scrollX, scrollY, -vx, -vy, 0, maxX, 0, maxY,
                 maxX == 0 ? 0 : overflingDistance, overflingDistance);
-        // Duration is calculated based on velocity. With range boundaries and overscroll
-        // we may not know how long the final animation will take. (Hence the deprecation
-        // warning on the call below.) It's not a big deal for scroll bars but if webcore
-        // resumes during this effect we will take a performance hit. See computeScroll;
-        // we resume webcore there when the animation is finished.
-        final int time = mScroller.getDuration();
-
-        // Suppress scrollbars for layer scrolling.
-        if (mTouchMode != TOUCH_DRAG_LAYER_MODE && mTouchMode != TOUCH_DRAG_TEXT_MODE) {
-            mWebViewPrivate.awakenScrollBars(time);
-        }
 
         invalidate();
     }
@@ -7362,17 +7271,6 @@
                 case DRAG_HELD_MOTIONLESS:
                     mHeldMotionless = MOTIONLESS_TRUE;
                     invalidate();
-                    // fall through to keep scrollbars awake
-
-                case AWAKEN_SCROLL_BARS:
-                    if (mTouchMode == TOUCH_DRAG_MODE
-                            && mHeldMotionless == MOTIONLESS_TRUE) {
-                        mWebViewPrivate.awakenScrollBars(ViewConfiguration
-                                .getScrollDefaultDelay(), false);
-                        mPrivateHandler.sendMessageDelayed(mPrivateHandler
-                                .obtainMessage(AWAKEN_SCROLL_BARS),
-                                ViewConfiguration.getScrollDefaultDelay());
-                    }
                     break;
 
                 case SCREEN_ON:
@@ -7467,9 +7365,9 @@
                     break;
 
                 case SELECTION_STRING_CHANGED:
-                    if (mAccessibilityInjector != null) {
-                        String selectionString = (String) msg.obj;
-                        mAccessibilityInjector.onSelectionStringChange(selectionString);
+                    if (isAccessibilityEnabled()) {
+                        getAccessibilityInjector()
+                                .handleSelectionChangedIfNecessary((String) msg.obj);
                     }
                     break;
 
@@ -7538,6 +7436,7 @@
                     int cursorPosition = start + text.length();
                     replaceTextfieldText(start, end, text,
                             cursorPosition, cursorPosition);
+                    selectionDone();
                     break;
                 }
 
@@ -7564,7 +7463,9 @@
                 }
 
                 case CLEAR_CARET_HANDLE:
-                    selectionDone();
+                    if (mIsCaretSelection) {
+                        selectionDone();
+                    }
                     break;
 
                 case KEY_PRESS:
@@ -7652,6 +7553,11 @@
                 invalidate();
             }
         }
+
+        @Override
+        public void clearPreviousHitTest() {
+            setHitTestResult(null);
+        }
     }
 
     private void setHitTestTypeFromUrl(String url) {
@@ -7969,7 +7875,7 @@
         nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
 
         if ((data.mSelectionReason == TextSelectionData.REASON_ACCESSIBILITY_INJECTOR)
-                || (!mSelectingText
+                || (!mSelectingText && data.mStart != data.mEnd
                         && data.mSelectionReason != TextSelectionData.REASON_SELECT_WORD)) {
             selectionDone();
             mShowTextSelectionExtra = true;
@@ -8025,7 +7931,7 @@
         mIsBatchingTextChanges = false;
     }
 
-    private void sendBatchableInputMessage(int what, int arg1, int arg2,
+    void sendBatchableInputMessage(int what, int arg1, int arg2,
             Object obj) {
         if (mWebViewCore == null) {
             return;
@@ -8446,16 +8352,6 @@
     }
 
     /**
-     * @return Whether accessibility script has been injected.
-     */
-    private boolean accessibilityScriptInjected() {
-        // TODO: Maybe the injected script should announce its presence in
-        // the page meta-tag so the nativePageShouldHandleShiftAndArrows
-        // will check that as one of the conditions it looks for
-        return mAccessibilityScriptInjected;
-    }
-
-    /**
      * See {@link WebView#setBackgroundColor(int)}
      */
     @Override
@@ -8601,6 +8497,11 @@
         mWebView.postInvalidate();
     }
 
+    // Note: must be called before first WebViewClassic is created.
+    public static void setShouldMonitorWebCoreThread() {
+        WebViewCore.setShouldMonitorWebCoreThread();
+    }
+
     private native void     nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx);
     private native void     nativeDebugDump();
     private native void     nativeDestroy();
@@ -8617,7 +8518,8 @@
     private native String   nativeGetSelection();
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native boolean  nativeSetBaseLayer(int nativeInstance,
-            int layer, boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
+            int layer, boolean showVisualIndicator, boolean isPictureAfterFirstLayout,
+            int scrollingLayer);
     private native int      nativeGetBaseLayer(int nativeInstance);
     private native void     nativeCopyBaseContentToPicture(Picture pict);
     private native boolean  nativeHasContent();
@@ -8661,4 +8563,6 @@
             Rect rect);
     // Returns 1 if a layer sync is needed, else 0
     private static native int nativeSetHwAccelerated(int instance, boolean hwAccelerated);
+    private static native void nativeFindMaxVisibleRect(int instance, int layerId,
+            Rect visibleContentRect);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 76cd1c9..1164649 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -144,6 +144,11 @@
     private int mChromeCanFocusDirection;
     private int mTextSelectionChangeReason = TextSelectionData.REASON_UNKNOWN;
 
+    // Used to determine if we should monitor the WebCore thread for responsiveness.
+    // If it "hangs", for example a web page enters a while(true) loop, we will
+    // prompt the user with a dialog allowing them to terminate the process.
+    private static boolean sShouldMonitorWebCoreThread;
+
     // The thread name used to identify the WebCore thread and for use in
     // debugging other classes that require operation within the WebCore thread.
     /* package */ static final String THREAD_NAME = "WebViewCoreThread";
@@ -176,10 +181,16 @@
                     Log.e(LOGTAG, Log.getStackTraceString(e));
                 }
 
-                // Start the singleton watchdog which will monitor the WebCore thread
-                // to verify it's still processing messages.
-                WebCoreThreadWatchdog.start(context, sWebCoreHandler);
+                if (sShouldMonitorWebCoreThread) {
+                    // Start the singleton watchdog which will monitor the WebCore thread
+                    // to verify it's still processing messages. Note that this is the only
+                    // time we need to check the value as all the other public methods on
+                    // the WebCoreThreadWatchdog are no-ops if start() is not called.
+                    WebCoreThreadWatchdog.start(sWebCoreHandler);
+                }
             }
+            // Make sure the Watchdog is aware of this new WebView.
+            WebCoreThreadWatchdog.registerWebView(w);
         }
         // Create an EventHub to handle messages before and after the thread is
         // ready.
@@ -658,7 +669,7 @@
             int x, int y);
     private native boolean nativeMouseClick(int nativeClass);
 
-    private native boolean nativeHandleTouchEvent(int nativeClass, int action,
+    private native int nativeHandleTouchEvent(int nativeClass, int action,
             int[] idArray, int[] xArray, int[] yArray, int count,
             int actionIndex, int metaState);
 
@@ -957,6 +968,9 @@
     static final int ACTION_LONGPRESS = 0x100;
     static final int ACTION_DOUBLETAP = 0x200;
 
+    private static final int TOUCH_FLAG_HIT_HANDLER = 0x1;
+    private static final int TOUCH_FLAG_PREVENT_DEFAULT = 0x2;
+
     static class TouchEventData {
         int mAction;
         int[] mIds;  // Ids of the touch points
@@ -1773,7 +1787,8 @@
         }
 
         @Override
-        public boolean dispatchWebKitEvent(MotionEvent event, int eventType, int flags) {
+        public boolean dispatchWebKitEvent(WebViewInputDispatcher dispatcher,
+                MotionEvent event, int eventType, int flags) {
             if (mNativeClass == 0) {
                 return false;
             }
@@ -1800,10 +1815,16 @@
                         xArray[i] = (int) event.getX(i);
                         yArray[i] = (int) event.getY(i);
                     }
-                    return nativeHandleTouchEvent(mNativeClass,
+                    int touchFlags = nativeHandleTouchEvent(mNativeClass,
                             event.getActionMasked(),
                             idArray, xArray, yArray, count,
                             event.getActionIndex(), event.getMetaState());
+                    if (touchFlags == 0
+                            && event.getActionMasked() != MotionEvent.ACTION_CANCEL
+                            && (flags & WebViewInputDispatcher.FLAG_PRIVATE) == 0) {
+                        dispatcher.skipWebkitForRemainingTouchStream();
+                    }
+                    return (touchFlags & TOUCH_FLAG_PREVENT_DEFAULT) > 0;
                 }
 
                 default:
@@ -1979,6 +2000,7 @@
             mEventHub.sendMessageAtFrontOfQueue(
                     Message.obtain(null, EventHub.DESTROY));
             mEventHub.blockMessages();
+            WebCoreThreadWatchdog.unregisterWebView(mWebViewClassic);
         }
     }
 
@@ -3058,6 +3080,10 @@
         return mDeviceOrientationService;
     }
 
+    static void setShouldMonitorWebCoreThread() {
+        sShouldMonitorWebCoreThread = true;
+    }
+
     private native void nativeSetIsPaused(int nativeClass, boolean isPaused);
     private native void nativePause(int nativeClass);
     private native void nativeResume(int nativeClass);
diff --git a/core/java/android/webkit/WebViewInputDispatcher.java b/core/java/android/webkit/WebViewInputDispatcher.java
index 9eeb311..d8065e9 100644
--- a/core/java/android/webkit/WebViewInputDispatcher.java
+++ b/core/java/android/webkit/WebViewInputDispatcher.java
@@ -399,7 +399,6 @@
         unscheduleHideTapHighlightLocked();
         unscheduleShowTapHighlightLocked();
         mUiCallbacks.showTapHighlight(true);
-        scheduleHideTapHighlightLocked();
     }
 
     private void scheduleShowTapHighlightLocked() {
@@ -466,13 +465,13 @@
                 return;
             }
             mPostClickScheduled = false;
-            showTapCandidateLocked();
 
             MotionEvent event = mPostTouchStream.getLastEvent();
             if (event == null || event.getAction() != MotionEvent.ACTION_UP) {
                 return;
             }
 
+            showTapCandidateLocked();
             MotionEvent eventToEnqueue = MotionEvent.obtainNoHistory(event);
             DispatchEvent d = obtainDispatchEventLocked(eventToEnqueue, EVENT_TYPE_CLICK, 0,
                     mPostLastWebKitXOffset, mPostLastWebKitYOffset, mPostLastWebKitScale);
@@ -511,6 +510,7 @@
     }
 
     private void enqueueHitTestLocked(MotionEvent event) {
+        mUiCallbacks.clearPreviousHitTest();
         MotionEvent eventToEnqueue = MotionEvent.obtainNoHistory(event);
         DispatchEvent d = obtainDispatchEventLocked(eventToEnqueue, EVENT_TYPE_HIT_TEST, 0,
                 mPostLastWebKitXOffset, mPostLastWebKitYOffset, mPostLastWebKitScale);
@@ -553,12 +553,17 @@
             mIsTapCandidate = true;
             mInitialDownX = event.getX();
             mInitialDownY = event.getY();
-            scheduleShowTapHighlightLocked();
             enqueueHitTestLocked(event);
+            if (mIsDoubleTapCandidate) {
+                hideTapCandidateLocked();
+            } else {
+                scheduleShowTapHighlightLocked();
+            }
         } else if (action == MotionEvent.ACTION_UP) {
             unscheduleLongPressLocked();
             if (isClickCandidateLocked(event)) {
                 if (mIsDoubleTapCandidate) {
+                    hideTapCandidateLocked();
                     enqueueDoubleTapLocked(event);
                 } else {
                     scheduleClickLocked();
@@ -666,6 +671,10 @@
                 if (event != null && recycleEvent) {
                     event.recycle();
                 }
+
+                if (eventType == EVENT_TYPE_CLICK) {
+                    scheduleHideTapHighlightLocked();
+                }
             }
         }
     }
@@ -677,7 +686,7 @@
                     + ", eventType=" + eventType + ", flags=" + flags);
         }
         boolean preventDefault = mWebKitCallbacks.dispatchWebKitEvent(
-                event, eventType, flags);
+                this, event, eventType, flags);
         if (DEBUG) {
             Log.d(TAG, "dispatchWebKitEvent: preventDefault=" + preventDefault);
         }
@@ -701,6 +710,12 @@
         mWebKitDispatchEventQueue.mHead = d;
     }
 
+    // Called by WebKit when it doesn't care about the rest of the touch stream
+    public void skipWebkitForRemainingTouchStream() {
+        // Just treat this like a timeout
+        handleWebKitTimeout();
+    }
+
     // Runs on UI thread in response to the web kit thread appearing to be unresponsive.
     private void handleWebKitTimeout() {
         synchronized (mLock) {
@@ -802,6 +817,10 @@
                     d.mEvent = null; // retain ownership of event, don't recycle it yet
                 }
                 recycleDispatchEventLocked(d);
+
+                if (eventType == EVENT_TYPE_CLICK) {
+                    scheduleHideTapHighlightLocked();
+                }
             }
 
             // Handle the event.
@@ -822,21 +841,31 @@
     }
 
     private void enqueueEventLocked(DispatchEvent d) {
-        if (!shouldSkipWebKit(d.mEventType)) {
+        if (!shouldSkipWebKit(d)) {
             enqueueWebKitEventLocked(d);
         } else {
             enqueueUiEventLocked(d);
         }
     }
 
-    private boolean shouldSkipWebKit(int eventType) {
-        switch (eventType) {
+    private boolean shouldSkipWebKit(DispatchEvent d) {
+        switch (d.mEventType) {
             case EVENT_TYPE_CLICK:
             case EVENT_TYPE_HOVER:
             case EVENT_TYPE_SCROLL:
             case EVENT_TYPE_HIT_TEST:
                 return false;
             case EVENT_TYPE_TOUCH:
+                // TODO: This should be cleaned up. We now have WebViewInputDispatcher
+                // and WebViewClassic both checking for slop and doing their own
+                // thing - they should be consolidated. And by consolidated, I mean
+                // WebViewClassic's version should just be deleted.
+                // The reason this is done is because webpages seem to expect
+                // that they only get an ontouchmove if the slop has been exceeded.
+                if (mIsTapCandidate && d.mEvent != null
+                        && d.mEvent.getActionMasked() == MotionEvent.ACTION_MOVE) {
+                    return true;
+                }
                 return !mPostSendTouchEventsToWebKit
                         || mPostDoNotSendTouchEventsToWebKitUntilNextGesture;
         }
@@ -1040,6 +1069,12 @@
          * @param show True if it should show the highlight, false if it should hide it
          */
         public void showTapHighlight(boolean show);
+
+        /**
+         * Called when we are sending a new EVENT_TYPE_HIT_TEST to WebKit, so
+         * previous hit tests should be cleared as they are obsolete.
+         */
+        public void clearPreviousHitTest();
     }
 
     /* Implemented by {@link WebViewCore} to perform operations on the web kit thread. */
@@ -1052,12 +1087,14 @@
 
         /**
          * Dispatches an event to web kit.
+         * @param dispatcher The WebViewInputDispatcher sending the event
          * @param event The event.
          * @param eventType The event type.
          * @param flags The event's dispatch flags.
          * @return True if web kit wants to prevent default event handling.
          */
-        public boolean dispatchWebKitEvent(MotionEvent event, int eventType, int flags);
+        public boolean dispatchWebKitEvent(WebViewInputDispatcher dispatcher,
+                MotionEvent event, int eventType, int flags);
     }
 
     // Runs on UI thread.
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 74a215c..867ee54 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -276,6 +276,8 @@
 
         public void onInitializeAccessibilityEvent(AccessibilityEvent event);
 
+        public boolean performAccessibilityAction(int action, Bundle arguments);
+
         public void setOverScrollMode(int mode);
 
         public void setScrollBarStyle(int style);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 04c8cdc..9abe72b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -579,6 +579,7 @@
     private InputConnectionWrapper mPublicInputConnection;
 
     private Runnable mClearScrollingCache;
+    Runnable mPositionScrollAfterLayout;
     private int mMinimumVelocity;
     private int mMaximumVelocity;
     private float mVelocityScale = 1.0f;
@@ -1352,24 +1353,23 @@
             case ACCESSIBILITY_FOCUS_FORWARD: {
                 ViewRootImpl viewRootImpl = getViewRootImpl();
                 if (viewRootImpl == null) {
-                    break;
+                    return null;
                 }
                 View currentFocus = viewRootImpl.getAccessibilityFocusedHost();
                 if (currentFocus == null) {
-                    break;
+                    return super.focusSearch(this, direction);
                 }
                 // If we have the focus try giving it to the first child.
                 if (currentFocus == this) {
-                    final int firstVisiblePosition = getFirstVisiblePosition();
-                    if (firstVisiblePosition >= 0) {
+                    if (getChildCount() > 0) {
                         return getChildAt(0);
                     }
-                    return null;
+                    return super.focusSearch(this, direction);
                 }
                 // Find the item that has accessibility focus.
                 final int currentPosition = getPositionForView(currentFocus);
                 if (currentPosition < 0 || currentPosition >= getCount()) {
-                    break;
+                    return super.focusSearch(this, direction);
                 }
                 // Try to advance focus in the current item.
                 View currentItem = getChildAt(currentPosition - getFirstVisiblePosition());
@@ -1386,25 +1386,31 @@
                 final int nextPosition = currentPosition - getFirstVisiblePosition() + 1;
                 if (nextPosition < getChildCount()) {
                     return getChildAt(nextPosition);
+                } else {
+                    return super.focusSearch(this, direction);
                 }
-            } break;
+            }
             case ACCESSIBILITY_FOCUS_BACKWARD: {
                 ViewRootImpl viewRootImpl = getViewRootImpl();
                 if (viewRootImpl == null) {
-                    break;
+                    return null;
                 }
                 View currentFocus = viewRootImpl.getAccessibilityFocusedHost();
                 if (currentFocus == null) {
-                    break;
+                    return super.focusSearch(this, direction);
                 }
                 // If we have the focus do a generic search.
                 if (currentFocus == this) {
+                    final int lastChildIndex = getChildCount() - 1;
+                    if (lastChildIndex >= 0) {
+                        return getChildAt(lastChildIndex);
+                    }
                     return super.focusSearch(this, direction);
                 }
                 // Find the item that has accessibility focus.
                 final int currentPosition = getPositionForView(currentFocus);
                 if (currentPosition < 0 || currentPosition >= getCount()) {
-                    break;
+                    return super.focusSearch(this, direction);
                 }
                 // Try to advance focus in the current item.
                 View currentItem = getChildAt(currentPosition - getFirstVisiblePosition());
@@ -1422,7 +1428,7 @@
                 if (nextPosition >= 0) {
                     return getChildAt(nextPosition);
                 } else {
-                    return this;
+                    return super.focusSearch(this, direction);
                 }
             }
         }
@@ -1451,7 +1457,7 @@
             final int lastVisiblePosition = getLastVisiblePosition();
             if (mLastAccessibilityScrollEventFromIndex == firstVisiblePosition
                     && mLastAccessibilityScrollEventToIndex == lastVisiblePosition) {
-                return;   
+                return;
             } else {
                 mLastAccessibilityScrollEventFromIndex = firstVisiblePosition;
                 mLastAccessibilityScrollEventToIndex = lastVisiblePosition;
@@ -1470,11 +1476,13 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(AbsListView.class.getName());
-        if (getFirstVisiblePosition() > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
-        }
-        if (getLastVisiblePosition() < getCount() - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+        if (isEnabled()) {
+            if (getFirstVisiblePosition() > 0) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
+            if (getLastVisiblePosition() < getCount() - 1) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
         }
     }
 
@@ -1485,14 +1493,14 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (getLastVisiblePosition() < getCount() - 1) {
+                if (isEnabled() && getLastVisiblePosition() < getCount() - 1) {
                     final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
                     smoothScrollBy(viewportHeight, PositionScroller.SCROLL_DURATION);
                     return true;
                 }
             } return false;
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (mFirstPosition > 0) {
+                if (isEnabled() && mFirstPosition > 0) {
                     final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
                     smoothScrollBy(-viewportHeight, PositionScroller.SCROLL_DURATION);
                     return true;
@@ -1903,6 +1911,7 @@
         removeAllViewsInLayout();
         mFirstPosition = 0;
         mDataChanged = false;
+        mPositionScrollAfterLayout = null;
         mNeedSync = false;
         mOldSelectedPosition = INVALID_POSITION;
         mOldSelectedRowId = INVALID_ROW_ID;
@@ -2214,31 +2223,17 @@
 
         View child;
         if (scrapView != null) {
-            if (ViewDebug.TRACE_RECYCLER) {
-                ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.RECYCLE_FROM_SCRAP_HEAP,
-                        position, -1);
-            }
-
             child = mAdapter.getView(position, scrapView, this);
 
             if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                 child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
             }
 
-            if (ViewDebug.TRACE_RECYCLER) {
-                ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,
-                        position, getChildCount());
-            }
-
             if (child != scrapView) {
                 mRecycler.addScrapView(scrapView, position);
                 if (mCacheColorHint != 0) {
                     child.setDrawingCacheBackgroundColor(mCacheColorHint);
                 }
-                if (ViewDebug.TRACE_RECYCLER) {
-                    ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,
-                            position, -1);
-                }
             } else {
                 isScrap[0] = true;
                 child.dispatchFinishTemporaryDetach();
@@ -2253,10 +2248,6 @@
             if (mCacheColorHint != 0) {
                 child.setDrawingCacheBackgroundColor(mCacheColorHint);
             }
-            if (ViewDebug.TRACE_RECYCLER) {
-                ViewDebug.trace(child, ViewDebug.RecyclerTraceType.NEW_VIEW,
-                        position, getChildCount());
-            }
         }
 
         if (mAdapterHasStableIds) {
@@ -2289,11 +2280,27 @@
             super.onInitializeAccessibilityNodeInfo(host, info);
 
             final int position = getPositionForView(host);
+            final ListAdapter adapter = getAdapter();
 
-            if (position == INVALID_POSITION) {
+            if ((position == INVALID_POSITION) || (adapter == null)) {
+                // Cannot perform actions on invalid items.
+                info.setEnabled(false);
                 return;
             }
 
+            if (!isEnabled() || !adapter.isEnabled(position)) {
+                // Cannot perform actions on invalid items.
+                info.setEnabled(false);
+                return;
+            }
+
+            if (position == getSelectedItemPosition()) {
+                info.setSelected(true);
+                info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
+            } else {
+                info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+            }
+
             if (isClickable()) {
                 info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
                 info.setClickable(true);
@@ -2304,43 +2311,55 @@
                 info.setLongClickable(true);
             }
 
-            info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
-
-            if (position == getSelectedItemPosition()) {
-                info.setSelected(true);
-            }
         }
 
         @Override
         public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
-            final int position = getPositionForView(host);
+            if (super.performAccessibilityAction(host, action, arguments)) {
+                return true;
+            }
 
-            if (position == INVALID_POSITION) {
+            final int position = getPositionForView(host);
+            final ListAdapter adapter = getAdapter();
+
+            if ((position == INVALID_POSITION) || (adapter == null)) {
+                // Cannot perform actions on invalid items.
+                return false;
+            }
+
+            if (!isEnabled() || !adapter.isEnabled(position)) {
+                // Cannot perform actions on disabled items.
                 return false;
             }
 
             final long id = getItemIdAtPosition(position);
 
             switch (action) {
-                case AccessibilityNodeInfo.ACTION_SELECT:
-                    setSelection(position);
-                    return true;
-                case AccessibilityNodeInfo.ACTION_CLICK:
-                    if (!super.performAccessibilityAction(host, action, arguments)) {
+                case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
+                    if (getSelectedItemPosition() == position) {
+                        setSelection(INVALID_POSITION);
+                        return true;
+                    }
+                } return false;
+                case AccessibilityNodeInfo.ACTION_SELECT: {
+                    if (getSelectedItemPosition() != position) {
+                        setSelection(position);
+                        return true;
+                    }
+                } return false;
+                case AccessibilityNodeInfo.ACTION_CLICK: {
+                    if (isClickable()) {
                         return performItemClick(host, position, id);
                     }
-                    return true;
-                case AccessibilityNodeInfo.ACTION_LONG_CLICK:
-                    if (!super.performAccessibilityAction(host, action, arguments)) {
+                } return false;
+                case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+                    if (isLongClickable()) {
                         return performLongPress(host, position, id);
                     }
-                    return true;
-                case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
-                    smoothScrollToPosition(position);
-                    break;
+                } return false;
             }
 
-            return super.performAccessibilityAction(host, action, arguments);
+            return false;
         }
     }
 
@@ -4231,11 +4250,11 @@
 
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         start(position);
                     }
-                });
+                };
                 return;
             }
 
@@ -4282,11 +4301,11 @@
 
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         start(position, boundPosition);
                     }
-                });
+                };
                 return;
             }
 
@@ -4359,11 +4378,11 @@
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
                 final int postOffset = offset;
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         startWithOffset(position, postOffset, duration);
                     }
-                });
+                };
                 return;
             }
 
@@ -4929,12 +4948,6 @@
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
                         mRecycler.addScrapView(child, position);
-
-                        if (ViewDebug.TRACE_RECYCLER) {
-                            ViewDebug.trace(child,
-                                    ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,
-                                    firstPosition + i, -1);
-                        }
                     }
                 }
             }
@@ -4953,12 +4966,6 @@
                     int position = firstPosition + i;
                     if (position >= headerViewsCount && position < footerViewsStart) {
                         mRecycler.addScrapView(child, position);
-
-                        if (ViewDebug.TRACE_RECYCLER) {
-                            ViewDebug.trace(child,
-                                    ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,
-                                    firstPosition + i, -1);
-                        }
                     }
                 }
             }
@@ -5902,63 +5909,6 @@
         removeAllViewsInLayout();
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    protected boolean onConsistencyCheck(int consistency) {
-        boolean result = super.onConsistencyCheck(consistency);
-
-        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
-
-        if (checkLayout) {
-            // The active recycler must be empty
-            final View[] activeViews = mRecycler.mActiveViews;
-            int count = activeViews.length;
-            for (int i = 0; i < count; i++) {
-                if (activeViews[i] != null) {
-                    result = false;
-                    Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
-                            "AbsListView " + this + " has a view in its active recycler: " +
-                                    activeViews[i]);
-                }
-            }
-
-            // All views in the recycler must NOT be on screen and must NOT have a parent
-            final ArrayList<View> scrap = mRecycler.mCurrentScrap;
-            if (!checkScrap(scrap)) result = false;
-            final ArrayList<View>[] scraps = mRecycler.mScrapViews;
-            count = scraps.length;
-            for (int i = 0; i < count; i++) {
-                if (!checkScrap(scraps[i])) result = false;
-            }
-        }
-
-        return result;
-    }
-
-    private boolean checkScrap(ArrayList<View> scrap) {
-        if (scrap == null) return true;
-        boolean result = true;
-
-        final int count = scrap.size();
-        for (int i = 0; i < count; i++) {
-            final View view = scrap.get(i);
-            if (view.getParent() != null) {
-                result = false;
-                Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
-                        " has a view in its scrap heap still attached to a parent: " + view);
-            }
-            if (indexOfChild(view) >= 0) {
-                result = false;
-                Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
-                        " has a view in its scrap heap that is also a direct child: " + view);
-            }
-        }
-
-        return result;
-    }
-
     private void finishGlows() {
         if (mEdgeGlowTop != null) {
             mEdgeGlowTop.finish();
@@ -6514,12 +6464,6 @@
                     if (hasListener) {
                         mRecyclerListener.onMovedToScrapHeap(victim);
                     }
-
-                    if (ViewDebug.TRACE_RECYCLER) {
-                        ViewDebug.trace(victim,
-                                ViewDebug.RecyclerTraceType.MOVE_FROM_ACTIVE_TO_SCRAP_HEAP,
-                                mFirstActivePosition + i, -1);
-                    }
                 }
             }
 
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index ae68794..e217e4f 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -21,6 +21,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -486,5 +487,46 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(AbsSeekBar.class.getName());
+
+        if (isEnabled()) {
+            final int progress = getProgress();
+            if (progress > 0) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
+            if (progress < getMax()) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (super.performAccessibilityAction(action, arguments)) {
+            return true;
+        }
+        if (!isEnabled()) {
+            return false;
+        }
+        final int progress = getProgress();
+        final int increment = Math.max(1, Math.round((float) getMax() / 5));
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                if (progress <= 0) {
+                    return false;
+                }
+                setProgress(progress - increment, true);
+                onKeyChange();
+                return true;
+            }
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                if (progress >= getMax()) {
+                    return false;
+                }
+                setProgress(progress + increment, true);
+                onKeyChange();
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index be6b4e2..4eb169b 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -400,6 +400,9 @@
         if (viewTreeObserver.isAlive()) {
             viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
         }
+        if (isShowingPopup()) {
+            dismissPopup();
+        }
         mIsAttachedToWindow = false;
     }
 
@@ -420,9 +423,7 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         mActivityChooserContent.layout(0, 0, right - left, bottom - top);
-        if (getListPopupWindow().isShowing()) {
-            showPopupUnchecked(mAdapter.getMaxActivityCount());
-        } else {
+        if (!isShowingPopup()) {
             dismissPopup();
         }
     }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index b2c8164..e4e7239 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -56,7 +56,12 @@
  * @attr ref android.R.styleable#Gallery_animationDuration
  * @attr ref android.R.styleable#Gallery_spacing
  * @attr ref android.R.styleable#Gallery_gravity
+ * 
+ * @deprecated This widget is no longer supported. Other horizontally scrolling
+ * widgets include {@link HorizontalScrollView} and {@link android.support.v4.view.ViewPager}
+ * from the support library.
  */
+@Deprecated
 @Widget
 public class Gallery extends AbsSpinner implements GestureDetector.OnGestureListener {
 
@@ -1369,11 +1374,13 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(Gallery.class.getName());
         info.setScrollable(mItemCount > 1);
-        if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-        }
-        if (mItemCount > 0 && mSelectedPosition > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+        if (isEnabled()) {
+            if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
+            if (isEnabled() && mItemCount > 0 && mSelectedPosition > 0) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
         }
     }
 
@@ -1384,13 +1391,13 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+                if (isEnabled() && mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
                     final int currentChildIndex = mSelectedPosition - mFirstPosition;
                     return scrollToChild(currentChildIndex + 1);
                 }
             } return false;
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (mItemCount > 0 && mSelectedPosition > 0) {
+                if (isEnabled() && mItemCount > 0 && mSelectedPosition > 0) {
                     final int currentChildIndex = mSelectedPosition - mFirstPosition;
                     return scrollToChild(currentChildIndex - 1);
                 }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 60a1d15..772d748 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -294,8 +294,32 @@
     }
 
     /**
-     * Orientation is used only to generate default row/column indices when
-     * they are not specified by a component's layout parameters.
+     *
+     * GridLayout uses the orientation property for two purposes:
+     * <ul>
+     *  <li>
+     *      To control the 'direction' in which default row/column indices are generated
+     *      when they are not specified in a component's layout parameters.
+     *  </li>
+     *  <li>
+     *      To control which axis should be processed first during the layout operation:
+     *      when orientation is {@link #HORIZONTAL} the horizontal axis is laid out first.
+     *  </li>
+     * </ul>
+     *
+     * The order in which axes are laid out is important if, for example, the height of
+     * one of GridLayout's children is dependent on its width - and its width is, in turn,
+     * dependent on the widths of other components.
+     * <p>
+     * If your layout contains a {@link TextView} (or derivative:
+     * {@code Button}, {@code EditText}, {@code CheckBox}, etc.) which is
+     * in multi-line mode (the default) it is normally best to leave GridLayout's
+     * orientation as {@code HORIZONTAL} - because {@code TextView} is capable of
+     * deriving its height for a given width, but not the other way around.
+     * <p>
+     * Other than the effects above, orientation does not affect the actual layout operation of
+     * GridLayout, so it's fine to leave GridLayout in {@code HORIZONTAL} mode even if
+     * the height of the intended layout greatly exceeds its width.
      * <p>
      * The default value of this property is {@link #HORIZONTAL}.
      *
@@ -1373,6 +1397,7 @@
                             break;
                         }
                         case PENDING: {
+                            // le singe est dans l'arbre
                             assert false;
                             break;
                         }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 0a40d5e..8975109 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1275,6 +1275,10 @@
 
             mLayoutMode = LAYOUT_NORMAL;
             mDataChanged = false;
+            if (mPositionScrollAfterLayout != null) {
+                post(mPositionScrollAfterLayout);
+                mPositionScrollAfterLayout = null;
+            }
             mNeedSync = false;
             setNextSelectedPositionInt(mSelectedPosition);
 
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index f889cb7..8c6ce19 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -744,6 +744,9 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                if (!isEnabled()) {
+                    return false;
+                }
                 final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
                 final int targetScrollX = Math.min(mScrollX + viewportWidth, getScrollRange());
                 if (targetScrollX != mScrollX) {
@@ -752,6 +755,9 @@
                 }
             } return false;
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                if (!isEnabled()) {
+                    return false;
+                }
                 final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
                 final int targetScrollX = Math.max(0, mScrollX - viewportWidth);
                 if (targetScrollX != mScrollX) {
@@ -770,10 +776,10 @@
         final int scrollRange = getScrollRange();
         if (scrollRange > 0) {
             info.setScrollable(true);
-            if (mScrollX > 0) {
+            if (isEnabled() && mScrollX > 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
-            if (mScrollX < scrollRange) {
+            if (isEnabled() && mScrollX < scrollRange) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5098523..d2e55d9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1557,10 +1557,6 @@
             if (dataChanged) {
                 for (int i = 0; i < childCount; i++) {
                     recycleBin.addScrapView(getChildAt(i), firstPosition+i);
-                    if (ViewDebug.TRACE_RECYCLER) {
-                        ViewDebug.trace(getChildAt(i),
-                                ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);
-                    }
                 }
             } else {
                 recycleBin.fillActiveViews(childCount, firstPosition);
@@ -1695,6 +1691,10 @@
             
             mLayoutMode = LAYOUT_NORMAL;
             mDataChanged = false;
+            if (mPositionScrollAfterLayout != null) {
+                post(mPositionScrollAfterLayout);
+                mPositionScrollAfterLayout = null;
+            }
             mNeedSync = false;
             setNextSelectedPositionInt(mSelectedPosition);
 
@@ -1757,11 +1757,6 @@
             // Try to use an existing view for this position
             child = mRecycler.getActiveView(position);
             if (child != null) {
-                if (ViewDebug.TRACE_RECYCLER) {
-                    ViewDebug.trace(child, ViewDebug.RecyclerTraceType.RECYCLE_FROM_ACTIVE_HEAP,
-                            position, getChildCount());
-                }
-
                 // Found it -- we're using an existing child
                 // This just needs to be positioned
                 setupChild(child, position, y, flow, childrenLeft, selected, true);
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 515f0c4..b60ffc5 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -2173,13 +2173,15 @@
                             return false;
                         }
                         case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                            if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+                            if (NumberPicker.this.isEnabled()
+                                    && (getWrapSelectorWheel() || getValue() < getMaxValue())) {
                                 changeValueByOne(true);
                                 return true;
                             }
                         } return false;
                         case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                            if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+                            if (NumberPicker.this.isEnabled()
+                                    && (getWrapSelectorWheel() || getValue() > getMinValue())) {
                                 changeValueByOne(false);
                                 return true;
                             }
@@ -2189,20 +2191,23 @@
                 case VIRTUAL_VIEW_ID_INPUT: {
                     switch (action) {
                         case AccessibilityNodeInfo.ACTION_FOCUS: {
-                            if (!mInputText.isFocused()) {
+                            if (NumberPicker.this.isEnabled() && !mInputText.isFocused()) {
                                 return mInputText.requestFocus();
                             }
                         } break;
                         case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
-                            if (mInputText.isFocused()) {
+                            if (NumberPicker.this.isEnabled() && mInputText.isFocused()) {
                                 mInputText.clearFocus();
                                 return true;
                             }
                             return false;
                         }
                         case AccessibilityNodeInfo.ACTION_CLICK: {
-                            showSoftInput();
-                            return true;
+                            if (NumberPicker.this.isEnabled()) {
+                                showSoftInput();
+                                return true;
+                            }
+                            return false;
                         }
                         case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
                             if (mAccessibilityFocusedView != virtualViewId) {
@@ -2230,10 +2235,13 @@
                 case VIRTUAL_VIEW_ID_INCREMENT: {
                     switch (action) {
                         case AccessibilityNodeInfo.ACTION_CLICK: {
-                            NumberPicker.this.changeValueByOne(true);
-                            sendAccessibilityEventForVirtualView(virtualViewId,
-                                    AccessibilityEvent.TYPE_VIEW_CLICKED);
-                        } return true;
+                            if (NumberPicker.this.isEnabled()) {
+                                NumberPicker.this.changeValueByOne(true);
+                                sendAccessibilityEventForVirtualView(virtualViewId,
+                                        AccessibilityEvent.TYPE_VIEW_CLICKED);
+                                return true;
+                            }
+                        } return false;
                         case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
                             if (mAccessibilityFocusedView != virtualViewId) {
                                 mAccessibilityFocusedView = virtualViewId;
@@ -2257,11 +2265,14 @@
                 case VIRTUAL_VIEW_ID_DECREMENT: {
                     switch (action) {
                         case AccessibilityNodeInfo.ACTION_CLICK: {
-                            final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT);
-                            NumberPicker.this.changeValueByOne(increment);
-                            sendAccessibilityEventForVirtualView(virtualViewId,
-                                    AccessibilityEvent.TYPE_VIEW_CLICKED);
-                        } return true;
+                            if (NumberPicker.this.isEnabled()) {
+                                final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT);
+                                NumberPicker.this.changeValueByOne(increment);
+                                sendAccessibilityEventForVirtualView(virtualViewId,
+                                        AccessibilityEvent.TYPE_VIEW_CLICKED);
+                                return true;
+                            }
+                        } return false;
                         case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
                             if (mAccessibilityFocusedView != virtualViewId) {
                                 mAccessibilityFocusedView = virtualViewId;
@@ -2470,7 +2481,9 @@
             if (mAccessibilityFocusedView == virtualViewId) {
                 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             }
-            info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+            if (NumberPicker.this.isEnabled()) {
+                info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+            }
 
             return info;
         }
@@ -2509,11 +2522,13 @@
             if (mAccessibilityFocusedView == View.NO_ID) {
                 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             }
-            if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-            }
-            if (getWrapSelectorWheel() || getValue() > getMinValue()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            if (NumberPicker.this.isEnabled()) {
+                if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+                    info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+                }
+                if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+                    info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+                }
             }
 
             return info;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5fa4ad0..f442912 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1253,13 +1253,13 @@
             unregisterForScrollChanged();
 
             try {
-                mWindowManager.removeView(mPopupView);                
+                mWindowManager.removeViewImmediate(mPopupView);
             } finally {
                 if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
                     ((ViewGroup) mPopupView).removeView(mContentView);
                 }
                 mPopupView = null;
-    
+
                 if (mOnDismissListener != null) {
                     mOnDismissListener.onDismiss();
                 }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 56c4bd8..1985792 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -37,6 +37,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater.Filter;
 import android.view.RemotableViewMethod;
@@ -1182,6 +1183,87 @@
     }
 
     /**
+     * Helper action to set text size on a TextView in any supported units.
+     */
+    private class TextViewSizeAction extends Action {
+        public TextViewSizeAction(int viewId, int units, float size) {
+            this.viewId = viewId;
+            this.units = units;
+            this.size = size;
+        }
+
+        public TextViewSizeAction(Parcel parcel) {
+            viewId = parcel.readInt();
+            units = parcel.readInt();
+            size  = parcel.readFloat();
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            dest.writeInt(units);
+            dest.writeFloat(size);
+        }
+
+        @Override
+        public void apply(View root, ViewGroup rootParent) {
+            final Context context = root.getContext();
+            final TextView target = (TextView) root.findViewById(viewId);
+            if (target == null) return;
+            target.setTextSize(units, size);
+        }
+
+        int viewId;
+        int units;
+        float size;
+
+        public final static int TAG = 13;
+    }
+
+    /**
+     * Helper action to set padding on a View.
+     */
+    private class ViewPaddingAction extends Action {
+        public ViewPaddingAction(int viewId, int left, int top, int right, int bottom) {
+            this.viewId = viewId;
+            this.left = left;
+            this.top = top;
+            this.right = right;
+            this.bottom = bottom;
+        }
+
+        public ViewPaddingAction(Parcel parcel) {
+            viewId = parcel.readInt();
+            left = parcel.readInt();
+            top = parcel.readInt();
+            right = parcel.readInt();
+            bottom = parcel.readInt();
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            dest.writeInt(left);
+            dest.writeInt(top);
+            dest.writeInt(right);
+            dest.writeInt(bottom);
+        }
+
+        @Override
+        public void apply(View root, ViewGroup rootParent) {
+            final Context context = root.getContext();
+            final View target = root.findViewById(viewId);
+            if (target == null) return;
+            target.setPadding(left, top, right, bottom);
+        }
+
+        int viewId;
+        int left, top, right, bottom;
+
+        public final static int TAG = 14;
+    }
+
+    /**
      * Simple class used to keep track of memory usage in a RemoteViews.
      *
      */
@@ -1334,6 +1416,12 @@
                     case TextViewDrawableAction.TAG:
                         mActions.add(new TextViewDrawableAction(parcel));
                         break;
+                    case TextViewSizeAction.TAG:
+                        mActions.add(new TextViewSizeAction(parcel));
+                        break;
+                    case ViewPaddingAction.TAG:
+                        mActions.add(new ViewPaddingAction(parcel));
+                        break;
                     case BitmapReflectionAction.TAG:
                         mActions.add(new BitmapReflectionAction(parcel));
                         break;
@@ -1445,7 +1533,8 @@
     /**
      * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
      */
-    int estimateMemoryUsage() {
+    /** @hide */
+    public int estimateMemoryUsage() {
         return mMemoryUsageCounter.getMemoryUsage();
     }
 
@@ -1540,7 +1629,19 @@
     public void setTextViewText(int viewId, CharSequence text) {
         setCharSequence(viewId, "setText", text);
     }
-    
+
+    /**
+     * @hide
+     * Equivalent to calling {@link TextView#setTextSize(int, float)}
+     * 
+     * @param viewId The id of the view whose text size should change
+     * @param units The units of size (e.g. COMPLEX_UNIT_SP)
+     * @param size The size of the text
+     */
+    public void setTextViewTextSize(int viewId, int units, float size) {
+        addAction(new TextViewSizeAction(viewId, units, size));
+    }
+
     /**
      * Equivalent to calling 
      * {@link TextView#setCompoundDrawablesWithIntrinsicBounds(int, int, int, int)}.
@@ -1798,6 +1899,20 @@
     }
 
     /**
+     * @hide
+     * Equivalent to calling {@link View#setPadding(int, int, int, int)}.
+     *
+     * @param viewId The id of the view to change
+     * @param left the left padding in pixels
+     * @param top the top padding in pixels
+     * @param right the right padding in pixels
+     * @param bottom the bottom padding in pixels
+     */
+    public void setViewPadding(int viewId, int left, int top, int right, int bottom) {
+        addAction(new ViewPaddingAction(viewId, left, top, right, bottom));
+    }
+
+    /**
      * Call a method taking one boolean on a view in the layout for this RemoteViews.
      *
      * @param viewId The id of the view on which to call the method.
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index f266d50..46ec923 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -614,7 +614,7 @@
                     maxDistIndexNonRequested = i;
                     maxDistNonRequested = dist;
                 }
-                if (dist > maxDist) {
+                if (dist >= maxDist) {
                     // maxDist/maxDistIndex will store the index of the farthest position
                     // regardless of whether it was directly requested or not
                     maxDistIndex = i;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a499743..2a20c56 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -745,6 +745,9 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
+        if (!isEnabled()) {
+            return false;
+        }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
                 final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop;
@@ -770,14 +773,16 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(ScrollView.class.getName());
-        final int scrollRange = getScrollRange();
-        if (scrollRange > 0) {
-            info.setScrollable(true);
-            if (mScrollY > 0) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
-            }
-            if (mScrollY < scrollRange) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+        if (isEnabled()) {
+            final int scrollRange = getScrollRange();
+            if (scrollRange > 0) {
+                info.setScrollable(true);
+                if (mScrollY > 0) {
+                    info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+                }
+                if (mScrollY < scrollRange) {
+                    info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+                }
             }
         }
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 521597b..8f3a311 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -511,7 +511,7 @@
     public void setQuery(CharSequence query, boolean submit) {
         mQueryTextView.setText(query);
         if (query != null) {
-            mQueryTextView.setSelection(query.length());
+            mQueryTextView.setSelection(mQueryTextView.length());
             mUserQuery = query;
         }
 
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index dd0915b..293eda1 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1230,11 +1230,13 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(StackView.class.getName());
         info.setScrollable(getChildCount() > 1);
-        if (getDisplayedChild() < getChildCount() - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-        }
-        if (getDisplayedChild() > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+        if (isEnabled()) {
+            if (getDisplayedChild() < getChildCount() - 1) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
+            if (getDisplayedChild() > 0) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
         }
     }
 
@@ -1243,6 +1245,9 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
+        if (!isEnabled()) {
+            return false;
+        }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
                 if (getDisplayedChild() < getChildCount() - 1) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fc56e11..bd19f00 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -39,6 +39,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
 import android.text.Editable;
@@ -5625,6 +5626,7 @@
                       physicalWidth, false);
     }
 
+    /** @hide */
     @Override
     public void onResolvedLayoutDirectionReset() {
         if (mLayoutAlignment != null) {
@@ -7676,7 +7678,7 @@
                 mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
         final SpellCheckerSubtype subtype = textServicesManager.getCurrentSpellCheckerSubtype(true);
         if (subtype != null) {
-            locale = new Locale(subtype.getLocale());
+            locale = SpellCheckerSubtype.constructLocaleFromString(subtype.getLocale());
         }
         return locale;
     }
@@ -7704,14 +7706,23 @@
         super.onPopulateAccessibilityEvent(event);
 
         final boolean isPassword = hasPasswordTransformationMethod();
-        if (!isPassword) {
-            CharSequence text = getTextForAccessibility();
+        if (!isPassword || shouldSpeakPasswordsForAccessibility()) {
+            final CharSequence text = getTextForAccessibility();
             if (!TextUtils.isEmpty(text)) {
                 event.getText().add(text);
             }
         }
     }
 
+    /**
+     * @return true if the user has explicitly allowed accessibility services
+     * to speak passwords.
+     */
+    private boolean shouldSpeakPasswordsForAccessibility() {
+        return (Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) == 1);
+    }
+
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
@@ -7739,8 +7750,7 @@
             info.setText(getTextForAccessibility());
         }
 
-        if (TextUtils.isEmpty(getContentDescription())
-                && !TextUtils.isEmpty(mText)) {
+        if (TextUtils.isEmpty(getContentDescription()) && !TextUtils.isEmpty(mText)) {
             info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
             info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
             info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
@@ -8162,6 +8172,7 @@
         return mEditor.mInBatchEditControllers;
     }
 
+    /** @hide */
     @Override
     public void onResolvedTextDirectionChanged() {
         if (hasPasswordTransformationMethod()) {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 88d7e05..fafc113 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -120,7 +120,12 @@
      */
     public void cancel() {
         mTN.hide();
-        // TODO this still needs to cancel the inflight notification if any
+
+        try {
+            getService().cancelToast(mContext.getPackageName(), mTN);
+        } catch (RemoteException e) {
+            // Empty
+        }
     }
     
     /**
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 2cbd9cc902..234cb71 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -708,7 +708,15 @@
             anim.start();
         } else {
             mTopVisibilityView.setAlpha(1);
-            mContainerView.setTranslationY(0);
+            mTopVisibilityView.setTranslationY(0);
+            if (mContentView != null) {
+                mContentView.setTranslationY(0);
+            }
+            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
+                mSplitView.setAlpha(1);
+                mSplitView.setTranslationY(0);
+                mSplitView.setVisibility(View.VISIBLE);
+            }
             mShowListener.onAnimationEnd(null);
         }
         if (mOverlayLayout != null) {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index e9db9d9..3a2b647 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -92,7 +92,7 @@
         getWindowManager().getDefaultDisplay().getMetrics(metrics);
 
         mContent = new ImageView(this);
-        mContent.setImageResource(com.android.internal.R.drawable.platlogo);
+        mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt);
         mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         
         final int p = (int)(32 * metrics.density);
@@ -102,7 +102,7 @@
             @Override
             public void onClick(View v) {
                 mToast.show();
-                mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt);
+                mContent.setImageResource(com.android.internal.R.drawable.platlogo);
             }
         });
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 614f73f..7334ac3 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -20,6 +20,7 @@
 import com.android.internal.content.PackageMonitor;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -34,6 +35,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PatternMatcher;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -61,6 +65,7 @@
 public class ResolverActivity extends AlertActivity implements AdapterView.OnItemClickListener {
     private static final String TAG = "ResolverActivity";
 
+    private int mLaunchedFromUid;
     private ResolveListAdapter mAdapter;
     private PackageManager mPm;
     private boolean mAlwaysUseOption;
@@ -102,6 +107,12 @@
             boolean alwaysUseOption) {
         setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert);
         super.onCreate(savedInstanceState);
+        try {
+            mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+                    getActivityToken());
+        } catch (RemoteException e) {
+            mLaunchedFromUid = -1;
+        }
         mPm = getPackageManager();
         mAlwaysUseOption = alwaysUseOption;
         mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
@@ -118,9 +129,14 @@
         mIconDpi = am.getLauncherLargeIconDensity();
         mIconSize = am.getLauncherLargeIconSize();
 
-        mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
+        mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
+                mLaunchedFromUid);
         int count = mAdapter.getCount();
-        if (count > 1) {
+        if (mLaunchedFromUid < 0 || UserId.isIsolated(mLaunchedFromUid)) {
+            // Gulp!
+            finish();
+            return;
+        } else if (count > 1) {
             ap.mView = getLayoutInflater().inflate(R.layout.resolver_grid, null);
             mGrid = (GridView) ap.mView.findViewById(R.id.resolver_grid);
             mGrid.setAdapter(mAdapter);
@@ -146,9 +162,13 @@
 
         if (alwaysUseOption) {
             final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);
-            buttonLayout.setVisibility(View.VISIBLE);
-            mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
-            mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
+            if (buttonLayout != null) {
+                buttonLayout.setVisibility(View.VISIBLE);
+                mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
+                mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
+            } else {
+                mAlwaysUseOption = false;
+            }
         }
     }
 
@@ -207,6 +227,18 @@
             mPackageMonitor.unregister();
             mRegistered = false;
         }
+        if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+            // This resolver is in the unusual situation where it has been
+            // launched at the top of a new task.  We don't let it be added
+            // to the recent tasks shown to the user, and we need to make sure
+            // that each time we are launched we get the correct launching
+            // uid (not re-using the same resolver from an old launching uid),
+            // so we will now finish ourself since being no longer visible,
+            // the user probably can't get back to us.
+            if (!isChangingConfigurations()) {
+                finish();
+            }
+        }
     }
 
     @Override
@@ -363,17 +395,19 @@
         private final Intent[] mInitialIntents;
         private final List<ResolveInfo> mBaseResolveList;
         private final Intent mIntent;
+        private final int mLaunchedFromUid;
         private final LayoutInflater mInflater;
 
         private List<ResolveInfo> mCurrentResolveList;
         private List<DisplayResolveInfo> mList;
 
         public ResolveListAdapter(Context context, Intent intent,
-                Intent[] initialIntents, List<ResolveInfo> rList) {
+                Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {
             mIntent = new Intent(intent);
             mIntent.setComponent(null);
             mInitialIntents = initialIntents;
             mBaseResolveList = rList;
+            mLaunchedFromUid = launchedFromUid;
             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             rebuildList();
         }
@@ -400,6 +434,23 @@
                 mCurrentResolveList = mPm.queryIntentActivities(
                         mIntent, PackageManager.MATCH_DEFAULT_ONLY
                         | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
+                // Filter out any activities that the launched uid does not
+                // have permission for.  We don't do this when we have an explicit
+                // list of resolved activities, because that only happens when
+                // we are being subclassed, so we can safely launch whatever
+                // they gave us.
+                if (mCurrentResolveList != null) {
+                    for (int i=mCurrentResolveList.size()-1; i >= 0; i--) {
+                        ActivityInfo ai = mCurrentResolveList.get(i).activityInfo;
+                        int granted = ActivityManager.checkComponentPermission(
+                                ai.permission, mLaunchedFromUid,
+                                ai.applicationInfo.uid, ai.exported);
+                        if (granted != PackageManager.PERMISSION_GRANTED) {
+                            // Access not allowed!
+                            mCurrentResolveList.remove(i);
+                        }
+                    }
+                }
             }
             int N;
             if ((mCurrentResolveList != null) && ((N = mCurrentResolveList.size()) > 0)) {
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
index bbf5509..7687ad1 100644
--- a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
+++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
@@ -175,7 +175,7 @@
             height = Math.min(height, lp.maxHeight);
         }
 
-        if (heightIn != height) {
+        if (DEBUG && heightIn != height) {
             Log.d(TAG, this + "child view " + child + " " +
                   "measured out of bounds at " + heightIn +"px " +
                   "clamped to " + height + "px");
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 60cd895..8cd63ef 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -67,6 +67,7 @@
         public void onReleased(View v, int handle);
         public void onTrigger(View v, int target);
         public void onGrabbedStateChange(View v, int handle);
+        public void onFinishFinalAnimation();
     }
 
     // Tuneable parameters for animation
@@ -77,20 +78,23 @@
     private static final int HIDE_ANIMATION_DELAY = 200;
     private static final int HIDE_ANIMATION_DURATION = 200;
     private static final int SHOW_ANIMATION_DURATION = 200;
-    private static final int SHOW_ANIMATION_DELAY = 0;
+    private static final int SHOW_ANIMATION_DELAY = 50;
     private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
-    private static final long RING_EXPAND_DURATION = 200;
-    private static final float TARGET_INITIAL_POSITION_SCALE = 0.8f;
+    private static final float TARGET_SCALE_SELECTED = 0.8f;
+    private static final long INITIAL_SHOW_HANDLE_DURATION = 200;
+    private static final float TARGET_SCALE_UNSELECTED = 1.0f;
+    private static final float RING_SCALE_UNSELECTED = 0.5f;
+    private static final float RING_SCALE_SELECTED = 1.5f;
 
     private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut;
 
     private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
     private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
-    private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
-    private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>();
+    private AnimationBundle mChevronAnimations = new AnimationBundle();
+    private AnimationBundle mTargetAnimations = new AnimationBundle();
+    private AnimationBundle mHandleAnimations = new AnimationBundle();
     private ArrayList<String> mTargetDescriptions;
     private ArrayList<String> mDirectionDescriptions;
-    private Tweener mHandleAnimation;
     private OnTriggerListener mOnTriggerListener;
     private TargetDrawable mHandleDrawable;
     private TargetDrawable mOuterRing;
@@ -114,9 +118,46 @@
     private boolean mDragging;
     private int mNewTargetResources;
 
+    private class AnimationBundle extends ArrayList<Tweener> {
+        private static final long serialVersionUID = 0xA84D78726F127468L;
+        private boolean mSuspended;
+
+        public void start() {
+            if (mSuspended) return; // ignore attempts to start animations
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.start();
+            }
+        }
+
+        public void cancel() {
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.cancel();
+            }
+            clear();
+        }
+
+        public void stop() {
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.end();
+            }
+            clear();
+        }
+
+        public void setSuspended(boolean suspend) {
+            mSuspended = suspend;
+        }
+    };
+
     private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
         public void onAnimationEnd(Animator animator) {
             switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+            dispatchOnFinishFinalAnimation();
         }
     };
 
@@ -124,6 +165,7 @@
         public void onAnimationEnd(Animator animator) {
             ping();
             switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+            dispatchOnFinishFinalAnimation();
         }
     };
 
@@ -239,6 +281,7 @@
 
         a.recycle();
         setVibrateEnabled(mVibrationDuration > 0);
+        assignDefaultsIfNeeded();
     }
 
     private void dump() {
@@ -254,6 +297,21 @@
         Log.v(TAG, "VerticalOffset = " + mVerticalOffset);
     }
 
+    public void suspendAnimations() {
+        mChevronAnimations.setSuspended(true);
+        mTargetAnimations.setSuspended(true);
+        mHandleAnimations.setSuspended(true);
+    }
+
+    public void resumeAnimations() {
+        mChevronAnimations.setSuspended(false);
+        mTargetAnimations.setSuspended(false);
+        mHandleAnimations.setSuspended(false);
+        mChevronAnimations.start();
+        mTargetAnimations.start();
+        mHandleAnimations.start();
+    }
+
     @Override
     protected int getSuggestedMinimumWidth() {
         // View should be large enough to contain the background + handle and
@@ -307,7 +365,7 @@
                 stopHandleAnimation();
                 deactivateTargets();
                 showTargets(true);
-                mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
+                activateHandle();
                 setGrabbedState(OnTriggerListener.CENTER_HANDLE);
                 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
                     announceTargets();
@@ -326,6 +384,19 @@
         }
     }
 
+    private void activateHandle() {
+        mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
+        if (mAlwaysTrackFinger) {
+            mHandleAnimations.stop();
+            mHandleDrawable.setAlpha(0.0f);
+            mHandleAnimations.add(Tweener.to(mHandleDrawable, INITIAL_SHOW_HANDLE_DURATION,
+                    "ease", Ease.Cubic.easeIn,
+                    "alpha", 1.0f,
+                    "onUpdate", mUpdateListener));
+            mHandleAnimations.start();
+        }
+    }
+
     /**
      * Animation used to attract user's attention to the target button.
      * Assumes mChevronDrawables is an a list with an even number of chevrons filled with
@@ -334,12 +405,12 @@
     private void startChevronAnimation() {
         final float chevronStartDistance = mHandleDrawable.getWidth() * 0.8f;
         final float chevronStopDistance = mOuterRadius * 0.9f / 2.0f;
-        mChevronAnimations.clear();
         final float startScale = 0.5f;
         final float endScale = 2.0f;
-
         final int directionCount = mFeedbackCount > 0 ? mChevronDrawables.size()/mFeedbackCount : 0;
 
+        mChevronAnimations.stop();
+
         // Add an animation for all chevron drawables.  There are mFeedbackCount drawables
         // in each direction and directionCount directions.
         for (int direction = 0; direction < directionCount; direction++) {
@@ -367,24 +438,21 @@
                         "onUpdate", mUpdateListener));
             }
         }
+        mChevronAnimations.start();
     }
 
     private void stopChevronAnimation() {
-        for (Tweener anim : mChevronAnimations) {
-            anim.animator.end();
-        }
-        mChevronAnimations.clear();
+        mChevronAnimations.stop();
     }
 
     private void stopHandleAnimation() {
-        if (mHandleAnimation != null) {
-            mHandleAnimation.animator.end();
-            mHandleAnimation = null;
-        }
+        mHandleAnimations.stop();
     }
 
     private void deactivateTargets() {
-        for (TargetDrawable target : mTargetDrawables) {
+        final int count = mTargetDrawables.size();
+        for (int i = 0; i < count; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
             target.setState(TargetDrawable.STATE_INACTIVE);
         }
         mActiveTarget = -1;
@@ -408,19 +476,18 @@
 
     /**
      * Dispatches a trigger event to listener. Ignored if a listener is not set.
-     * @param whichHandle the handle that triggered the event.
+     * @param whichTarget the target that was triggered.
      */
-    private void dispatchTriggerEvent(int whichHandle) {
+    private void dispatchTriggerEvent(int whichTarget) {
         vibrate();
         if (mOnTriggerListener != null) {
-            mOnTriggerListener.onTrigger(this, whichHandle);
+            mOnTriggerListener.onTrigger(this, whichTarget);
         }
     }
 
-    private void dispatchGrabbedEvent(int whichHandler) {
-        vibrate();
+    private void dispatchOnFinishFinalAnimation() {
         if (mOnTriggerListener != null) {
-            mOnTriggerListener.onGrabbed(this, whichHandler);
+            mOnTriggerListener.onFinishFinalAnimation();
         }
     }
 
@@ -432,27 +499,29 @@
         hideTargets(true);
 
         // Highlight the selected one
-        mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
+        mHandleAnimations.cancel();
         if (targetHit) {
+            mHandleDrawable.setAlpha(0.0f);
             mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
             hideUnselected(activeTarget);
 
             // Inform listener of any active targets.  Typically only one will be active.
             if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
-            dispatchTriggerEvent(mActiveTarget);
+            dispatchTriggerEvent(activeTarget);
         }
 
         // Animate handle back to the center based on current state.
         int delay = targetHit ? RETURN_TO_HOME_DELAY : 0;
-        int duration = targetHit ? 0 : RETURN_TO_HOME_DURATION;
-        mHandleAnimation = Tweener.to(mHandleDrawable, duration,
+        int duration = RETURN_TO_HOME_DURATION;
+        mHandleAnimations.add(Tweener.to(mHandleDrawable, duration,
                 "ease", Ease.Quart.easeOut,
                 "delay", delay,
-                "alpha", 1.0f,
+                "alpha", mAlwaysTrackFinger ? 0.0f : 1.0f,
                 "x", 0,
                 "y", 0,
                 "onUpdate", mUpdateListener,
-                "onComplete", (mDragging && !targetHit) ? mResetListenerWithPing : mResetListener);
+                "onComplete", (mDragging && !targetHit) ? mResetListenerWithPing : mResetListener));
+        mHandleAnimations.start();
 
         setGrabbedState(OnTriggerListener.NO_HANDLE);
     }
@@ -467,14 +536,15 @@
     }
 
     private void hideTargets(boolean animate) {
-        if (mTargetAnimations.size() > 0) {
-            stopTargetAnimation();
-        }
+        mTargetAnimations.cancel();
         // Note: these animations should complete at the same time so that we can swap out
         // the target assets asynchronously from the setTargetResources() call.
         mAnimatingTargets = animate;
         final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
         final int delay = animate ? HIDE_ANIMATION_DELAY : 0;
+        final boolean targetSelected = mActiveTarget != -1;
+
+        final float targetScale = targetSelected ? TARGET_SCALE_SELECTED : TARGET_SCALE_UNSELECTED;
         final int length = mTargetDrawables.size();
         for (int i = 0; i < length; i++) {
             TargetDrawable target = mTargetDrawables.get(i);
@@ -482,13 +552,13 @@
             mTargetAnimations.add(Tweener.to(target, duration,
                     "ease", Ease.Cubic.easeOut,
                     "alpha", 0.0f,
-                    "scaleX", TARGET_INITIAL_POSITION_SCALE,
-                    "scaleY", TARGET_INITIAL_POSITION_SCALE,
+                    "scaleX", targetScale,
+                    "scaleY", targetScale,
                     "delay", delay,
                     "onUpdate", mUpdateListener));
         }
 
-        float ringScaleTarget = mActiveTarget != -1 ? 1.5f : 0.5f;
+        final float ringScaleTarget = targetSelected ? RING_SCALE_SELECTED : RING_SCALE_UNSELECTED;
         mTargetAnimations.add(Tweener.to(mOuterRing, duration,
                 "ease", Ease.Cubic.easeOut,
                 "alpha", 0.0f,
@@ -497,21 +567,22 @@
                 "delay", delay,
                 "onUpdate", mUpdateListener,
                 "onComplete", mTargetUpdateListener));
+
+        mTargetAnimations.start();
     }
 
     private void showTargets(boolean animate) {
-        if (mTargetAnimations.size() > 0) {
-            stopTargetAnimation();
-        }
+        mTargetAnimations.stop();
         mAnimatingTargets = animate;
         final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
+        final int duration = animate ? SHOW_ANIMATION_DURATION : 0;
         final int length = mTargetDrawables.size();
         for (int i = 0; i < length; i++) {
             TargetDrawable target = mTargetDrawables.get(i);
             target.setState(TargetDrawable.STATE_INACTIVE);
-            target.setScaleX(TARGET_INITIAL_POSITION_SCALE);
-            target.setScaleY(TARGET_INITIAL_POSITION_SCALE);
-            mTargetAnimations.add(Tweener.to(target, animate ? SHOW_ANIMATION_DURATION : 0,
+            target.setScaleX(TARGET_SCALE_SELECTED);
+            target.setScaleY(TARGET_SCALE_SELECTED);
+            mTargetAnimations.add(Tweener.to(target, duration,
                     "ease", Ease.Cubic.easeOut,
                     "alpha", 1.0f,
                     "scaleX", 1.0f,
@@ -519,9 +590,7 @@
                     "delay", delay,
                     "onUpdate", mUpdateListener));
         }
-        mOuterRing.setScaleX(0.5f);
-        mOuterRing.setScaleY(0.5f);
-        mTargetAnimations.add(Tweener.to(mOuterRing, animate ? RING_EXPAND_DURATION : 0,
+        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
                 "ease", Ease.Cubic.easeOut,
                 "alpha", 1.0f,
                 "scaleX", 1.0f,
@@ -529,13 +598,8 @@
                 "delay", delay,
                 "onUpdate", mUpdateListener,
                 "onComplete", mTargetUpdateListener));
-    }
 
-    private void stopTargetAnimation() {
-        for (Tweener anim : mTargetAnimations) {
-            anim.animator.end();
-        }
-        mTargetAnimations.clear();
+        mTargetAnimations.start();
     }
 
     private void vibrate() {
@@ -658,7 +722,6 @@
      *
      */
     public void ping() {
-        stopChevronAnimation();
         startChevronAnimation();
     }
 
@@ -671,7 +734,7 @@
     public void reset(boolean animate) {
         stopChevronAnimation();
         stopHandleAnimation();
-        stopTargetAnimation();
+        mTargetAnimations.stop();
         hideChevrons();
         hideTargets(animate);
         mHandleDrawable.setX(0);
@@ -721,9 +784,9 @@
     }
 
     private void handleDown(MotionEvent event) {
-       if (!trySwitchToFirstTouchState(event)) {
+        if (!trySwitchToFirstTouchState(event.getX(), event.getY())) {
             mDragging = false;
-            stopTargetAnimation();
+            mTargetAnimations.cancel();
             ping();
         }
     }
@@ -747,14 +810,11 @@
     }
 
     private void handleMove(MotionEvent event) {
-        if (!mDragging) {
-            trySwitchToFirstTouchState(event);
-            return;
-        }
-
         int activeTarget = -1;
         final int historySize = event.getHistorySize();
-        final boolean singleTarget = mTargetDrawables.size() == 1;
+        ArrayList<TargetDrawable> targets = mTargetDrawables;
+        int ntargets = targets.size();
+        final boolean singleTarget = ntargets == 1;
         float x = 0.0f;
         float y = 0.0f;
         for (int k = 0; k < historySize + 1; k++) {
@@ -768,25 +828,29 @@
             float limitX = tx * scale;
             float limitY = ty * scale;
 
-            if (singleTarget) {
-                // Snap to outer ring if there's only one target
-                float snapRadius = mOuterRadius - mSnapMargin;
-                if (touchRadius > snapRadius) {
-                    activeTarget = 0;
-                }
+            if (!mDragging) {
+                trySwitchToFirstTouchState(eventX, eventY);
             } else {
-                // If there's more than one target, snap to the closest one less than hitRadius away.
-                float best = Float.MAX_VALUE;
-                final float hitRadius2 = mHitRadius * mHitRadius;
-                for (int i = 0; i < mTargetDrawables.size(); i++) {
-                    // Snap to the first target in range
-                    TargetDrawable target = mTargetDrawables.get(i);
-                    float dx = limitX - target.getX();
-                    float dy = limitY - target.getY();
-                    float dist2 = dx*dx + dy*dy;
-                    if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
-                        activeTarget = i;
-                        best = dist2;
+                if (singleTarget) {
+                    // Snap to outer ring if there's only one target
+                    float snapRadius = mOuterRadius - mSnapMargin;
+                    if (touchRadius > snapRadius) {
+                        activeTarget = 0;
+                    }
+                } else {
+                    // For more than one target, snap to the closest one less than hitRadius away.
+                    float best = Float.MAX_VALUE;
+                    final float hitRadius2 = mHitRadius * mHitRadius;
+                    // Find first target in range
+                    for (int i = 0; i < ntargets; i++) {
+                        TargetDrawable target = targets.get(i);
+                        float dx = limitX - target.getX();
+                        float dy = limitY - target.getY();
+                        float dist2 = dx*dx + dy*dy;
+                        if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
+                            activeTarget = i;
+                            best = dist2;
+                        }
                     }
                 }
             }
@@ -794,16 +858,25 @@
             y = limitY;
         }
 
+        if (!mDragging) {
+            return;
+        }
+
         if (activeTarget != -1) {
             switchToState(STATE_SNAP, x,y);
-            TargetDrawable target = mTargetDrawables.get(activeTarget);
+            TargetDrawable target = targets.get(activeTarget);
             float newX = singleTarget ? x : target.getX();
             float newY = singleTarget ? y : target.getY();
             moveHandleTo(newX, newY, false);
+            mHandleAnimations.cancel();
+            mHandleDrawable.setAlpha(0.0f);
         } else {
             switchToState(STATE_TRACKING, x, y);
+            if (mActiveTarget != -1) {
+                mHandleAnimations.cancel();
+                mHandleDrawable.setAlpha(1.0f);
+            }
             moveHandleTo(x, y, false);
-            mHandleDrawable.setAlpha(1.0f);
         }
 
         // Draw handle outside parent's bounds
@@ -812,20 +885,17 @@
         if (mActiveTarget != activeTarget) {
             // Defocus the old target
             if (mActiveTarget != -1) {
-                TargetDrawable target = mTargetDrawables.get(mActiveTarget);
+                TargetDrawable target = targets.get(mActiveTarget);
                 if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
                     target.setState(TargetDrawable.STATE_INACTIVE);
-                    mHandleDrawable.setAlpha(1.0f);
                 }
             }
             // Focus the new target
             if (activeTarget != -1) {
-                TargetDrawable target = mTargetDrawables.get(activeTarget);
+                TargetDrawable target = targets.get(activeTarget);
                 if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
                     target.setState(TargetDrawable.STATE_FOCUSED);
-                    mHandleDrawable.setAlpha(0.0f);
                 }
-                dispatchGrabbedEvent(activeTarget);
                 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
                     String targetContentDescription = getTargetDescription(activeTarget);
                     announceText(targetContentDescription);
@@ -872,14 +942,12 @@
                 } else {
                     mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE);
                 }
-                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
+                mOnTriggerListener.onGrabbedStateChange(this, newState);
             }
         }
     }
 
-    private boolean trySwitchToFirstTouchState(MotionEvent event) {
-        final float x = event.getX();
-        final float y = event.getY();
+    private boolean trySwitchToFirstTouchState(float x, float y) {
         final float tx = x - mWaveCenterX;
         final float ty = y - mWaveCenterY;
         if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledTapRadiusSquared()) {
@@ -892,9 +960,9 @@
         return false;
     }
 
-    private void assignDefaultsIfNeeded(float centerX, float centerY) {
+    private void assignDefaultsIfNeeded() {
         if (mOuterRadius == 0.0f) {
-            mOuterRadius = 0.5f*(float) Math.hypot(centerX, centerY);
+            mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f;
         }
         if (mHitRadius == 0.0f) {
             // Use the radius of inscribed circle of the first target.
@@ -941,6 +1009,7 @@
         super.onLayout(changed, left, top, right, bottom);
         final int width = right - left;
         final int height = bottom - top;
+
         // Target placement width/height. This puts the targets on the greater of the ring
         // width or the specified outer radius.
         final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
@@ -950,8 +1019,6 @@
         float newWaveCenterY = mVerticalOffset + mVerticalInset
                 + Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
 
-        assignDefaultsIfNeeded(newWaveCenterX, newWaveCenterY);
-
         if (mInitialLayout) {
             hideChevrons();
             hideTargets(false);
@@ -976,9 +1043,12 @@
 
     private void updateTargetPositions(float centerX, float centerY) {
         // Reposition the target drawables if the view changed.
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            final TargetDrawable targetIcon = mTargetDrawables.get(i);
-            double angle = -2.0f * Math.PI * i / mTargetDrawables.size();
+        ArrayList<TargetDrawable> targets = mTargetDrawables;
+        final int size = targets.size();
+        final float alpha = (float) (-2.0f * Math.PI / size);
+        for (int i = 0; i < size; i++) {
+            final TargetDrawable targetIcon = targets.get(i);
+            final float angle = alpha * i;
             targetIcon.setPositionX(centerX);
             targetIcon.setPositionY(centerY);
             targetIcon.setX(mOuterRadius * (float) Math.cos(angle));
@@ -987,7 +1057,10 @@
     }
 
     private void updateChevronPositions(float centerX, float centerY) {
-        for (TargetDrawable target : mChevronDrawables) {
+        ArrayList<TargetDrawable> chevrons = mChevronDrawables;
+        final int size = chevrons.size();
+        for (int i = 0; i < size; i++) {
+            TargetDrawable target = chevrons.get(i);
             if (target != null) {
                 target.setPositionX(centerX);
                 target.setPositionY(centerY);
@@ -996,7 +1069,10 @@
     }
 
     private void hideChevrons() {
-        for (TargetDrawable chevron : mChevronDrawables) {
+        ArrayList<TargetDrawable> chevrons = mChevronDrawables;
+        final int size = chevrons.size();
+        for (int i = 0; i < size; i++) {
+            TargetDrawable chevron = chevrons.get(i);
             if (chevron != null) {
                 chevron.setAlpha(0.0f);
             }
@@ -1006,14 +1082,18 @@
     @Override
     protected void onDraw(Canvas canvas) {
         mOuterRing.draw(canvas);
-        for (TargetDrawable target : mTargetDrawables) {
+        final int ntargets = mTargetDrawables.size();
+        for (int i = 0; i < ntargets; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
             if (target != null) {
                 target.draw(canvas);
             }
         }
-        for (TargetDrawable target : mChevronDrawables) {
-            if (target != null) {
-                target.draw(canvas);
+        final int nchevrons = mChevronDrawables.size();
+        for (int i = 0; i < nchevrons; i++) {
+            TargetDrawable chevron = mChevronDrawables.get(i);
+            if (chevron != null) {
+                chevron.draw(canvas);
             }
         }
         mHandleDrawable.draw(canvas);
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
index bc8a62f..1d502ba 100644
--- a/core/java/com/android/internal/widget/multiwaveview/Tweener.java
+++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
@@ -122,7 +122,6 @@
             anim.addListener(listener);
         }
         anim.addListener(mCleanupListener);
-        anim.start();
 
         return tween;
     }
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index 9ae61bc..f2aaab7 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -16,6 +16,7 @@
 extern jfieldID gOptions_heightFieldID;
 extern jfieldID gOptions_mimeFieldID;
 extern jfieldID gOptions_mCancelID;
+extern jfieldID gOptions_bitmapFieldID;
 
 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format);
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index dd8e84f..b218bcd 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -29,6 +29,7 @@
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "Utils.h"
 #include "JNIHelp.h"
+#include "SkTScopedPtr.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include "android_util_Binder.h"
@@ -180,7 +181,8 @@
  * reportSizeToVM not supported
  */
 static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
-        int start_x, int start_y, int width, int height, jobject options) {
+                                int start_x, int start_y, int width, int height, jobject options) {
+    jobject tileBitmap = NULL;
     SkImageDecoder *decoder = brd->getDecoder();
     int sampleSize = 1;
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
@@ -199,12 +201,12 @@
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
         preferQualityOverSpeed = env->GetBooleanField(options,
                 gOptions_preferQualityOverSpeedFieldID);
+        // Get the bitmap for re-use if it exists.
+        tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
     }
 
     decoder->setDitherImage(doDither);
     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
-    SkBitmap*           bitmap = new SkBitmap;
-    SkAutoTDelete<SkBitmap>       adb(bitmap);
     AutoDecoderCancel   adc(options, decoder);
 
     // To fix the race condition in case "requestCancelDecode"
@@ -219,6 +221,17 @@
     region.fTop = start_y;
     region.fRight = start_x + width;
     region.fBottom = start_y + height;
+    SkBitmap* bitmap = NULL;
+    SkTScopedPtr<SkBitmap> adb;
+
+    if (tileBitmap != NULL) {
+        // Re-use bitmap.
+        bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap);
+    }
+    if (bitmap == NULL) {
+        bitmap = new SkBitmap;
+        adb.reset(bitmap);
+    }
 
     if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
         return nullObjectReturn("decoder->decodeRegion returned false");
@@ -235,12 +248,12 @@
                             getMimeTypeString(env, decoder->getFormat()));
     }
 
-    // detach bitmap from its autodeleter, since we want to own it now
-    adb.detach();
+    if (tileBitmap != NULL) {
+        return tileBitmap;
+    }
 
-    SkPixelRef* pr = bitmap->pixelRef();
-    // promise we will never change our pixels (great for sharing and pictures)
-    pr->setImmutable();
+    // detach bitmap from its autodeleter, since we want to own it now
+    adb.release();
 
     JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator();
     jbyteArray buff = allocator->getStorageObjAndReset();
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7146667..d422951 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -703,7 +703,7 @@
 #endif
     uint32_t ref = ident;
     if (resolve) {
-        block = res.resolveReference(&value, block, &ref);
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
 #if THROW_ON_BAD_ID
         if (block == BAD_INDEX) {
             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e3d11f2..82f8984 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -774,11 +774,12 @@
     float transform[16];
     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
 
-    surfaceTexture->updateTexImage();
-    surfaceTexture->getTransformMatrix(transform);
-    GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
+    if (surfaceTexture->updateTexImage() == NO_ERROR) {
+        surfaceTexture->getTransformMatrix(transform);
+        GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
 
-    LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
+        LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
+    }
 }
 
 static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dbc60f9..e3082ea 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1551,6 +1551,14 @@
         android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
+        <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
+         to ensure that only the system can bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
+        android:label="@string/permlab_bindAccessibilityService"
+        android:description="@string/permdesc_bindAccessibilityService"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a TextService (e.g. SpellCheckerService)
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
diff --git a/core/res/res/anim-land/task_close_enter.xml b/core/res/res/anim-land/task_close_enter.xml
index 805ff6c..facc42b 100644
--- a/core/res/res/anim-land/task_close_enter.xml
+++ b/core/res/res/anim-land/task_close_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="300"
+            android:duration="400"/>
 
-    <translate android:fromXDelta="-140%" android:toXDelta="0"
+    <translate android:fromXDelta="-120%" android:toXDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="300"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+            android:fromYScale=".5" android:toYScale="1.0"
+            android:pivotY="50%p" android:pivotX="0%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="300"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_close_exit.xml b/core/res/res/anim-land/task_close_exit.xml
index 3e97149..e104c33 100644
--- a/core/res/res/anim-land/task_close_exit.xml
+++ b/core/res/res/anim-land/task_close_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
+            android:duration="300"/>
 
-    <translate android:fromXDelta="0" android:toXDelta="140%"
+    <translate android:fromXDelta="0" android:toXDelta="120%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:duration="350"/>
+            android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="300"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.5"
+            android:fromYScale="1.0" android:toYScale="0.5"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="350" />
+            android:pivotY="50%p" android:pivotX="100%p"
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="300" />
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="700" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_enter.xml b/core/res/res/anim-land/task_open_enter.xml
index fb1c5d6..dc7c7a9 100644
--- a/core/res/res/anim-land/task_open_enter.xml
+++ b/core/res/res/anim-land/task_open_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="300"
+            android:duration="400"/>
 
-    <translate android:fromXDelta="140%" android:toXDelta="0"
+    <translate android:fromXDelta="120%" android:toXDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="300"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+            android:fromYScale=".5" android:toYScale="1.0"
+            android:pivotY="50%p" android:pivotX="100%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="300"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_exit.xml b/core/res/res/anim-land/task_open_exit.xml
index 8d15324..701afa6 100644
--- a/core/res/res/anim-land/task_open_exit.xml
+++ b/core/res/res/anim-land/task_open_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
+            android:duration="300"/>
 
-    <translate android:fromXDelta="0" android:toXDelta="-140%"
+    <translate android:fromXDelta="0" android:toXDelta="-120%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:duration="350"/>
+            android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="300"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.5"
+            android:fromYScale="1.0" android:toYScale="0.5"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="350" />
+            android:pivotY="50%p" android:pivotX="0%p"
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="300" />
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="700" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_close_enter.xml b/core/res/res/anim-port/task_close_enter.xml
index 1806eed..9a747a1 100644
--- a/core/res/res/anim-port/task_close_enter.xml
+++ b/core/res/res/anim-port/task_close_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="300"
+            android:duration="400"/>
 
-    <translate android:fromYDelta="-140%" android:toYDelta="0"
+    <translate android:fromYDelta="-120%" android:toYDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="300"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+            android:fromYScale=".5" android:toYScale="1.0"
+            android:pivotX="50%p" android:pivotY="0%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="300"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_close_exit.xml b/core/res/res/anim-port/task_close_exit.xml
index 958a7a2..35b1aa3 100644
--- a/core/res/res/anim-port/task_close_exit.xml
+++ b/core/res/res/anim-port/task_close_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
+            android:duration="300"/>
 
-    <translate android:fromYDelta="0" android:toYDelta="140%"
+    <translate android:fromYDelta="0" android:toYDelta="120%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:duration="350"/>
+            android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="300"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.5"
+            android:fromYScale="1.0" android:toYScale="0.5"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="350" />
+            android:pivotX="50%p" android:pivotY="100%p"
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="300" />
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="700" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_open_enter.xml b/core/res/res/anim-port/task_open_enter.xml
index 54a2d93..5e4ae18 100644
--- a/core/res/res/anim-port/task_open_enter.xml
+++ b/core/res/res/anim-port/task_open_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="300"
+            android:duration="400"/>
 
-    <translate android:fromYDelta="140%" android:toYDelta="0"
+    <translate android:fromYDelta="120%" android:toYDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="300"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+            android:fromYScale=".5" android:toYScale="1.0"
+            android:pivotX="50%p" android:pivotY="100%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="300"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-port/task_open_exit.xml b/core/res/res/anim-port/task_open_exit.xml
index 18e6550b..0ba35d7 100644
--- a/core/res/res/anim-port/task_open_exit.xml
+++ b/core/res/res/anim-port/task_open_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
+            android:duration="300"/>
 
-    <translate android:fromYDelta="0" android:toYDelta="-140%"
+    <translate android:fromYDelta="0" android:toYDelta="-120%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:duration="350"/>
+            android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="300"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.5"
+            android:fromYScale="1.0" android:toYScale="0.5"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="350" />
+            android:pivotX="50%p" android:pivotY="0%p"
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="300" />
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="700" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_enter.xml b/core/res/res/anim-sw720dp/task_close_enter.xml
index 1806eed..e25978b 100644
--- a/core/res/res/anim-sw720dp/task_close_enter.xml
+++ b/core/res/res/anim-sw720dp/task_close_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="500"
+            android:duration="400"/>
 
-    <translate android:fromYDelta="-140%" android:toYDelta="0"
+    <translate android:fromYDelta="-50%" android:toYDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="500"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".8" android:toXScale="1.0"
+            android:fromYScale=".8" android:toYScale="1.0"
+            android:pivotX="50%p" android:pivotY="0%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="500"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_exit.xml b/core/res/res/anim-sw720dp/task_close_exit.xml
index 958a7a2..2d7e2a6 100644
--- a/core/res/res/anim-sw720dp/task_close_exit.xml
+++ b/core/res/res/anim-sw720dp/task_close_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
             android:duration="350"/>
 
-    <translate android:fromYDelta="0" android:toYDelta="140%"
+    <translate android:fromYDelta="0" android:toYDelta="50%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
+            android:interpolator="@interpolator/accelerate_cubic"
             android:duration="350"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.8"
+            android:fromYScale="1.0" android:toYScale="0.8"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
+            android:pivotX="50%p" android:pivotY="100%p"
+            android:interpolator="@interpolator/accelerate_quad"
             android:duration="350" />
 
-    <!-- This is needed to keep the animation running while task_open_enter completes -->
+    <!-- This is needed to keep the animation running while task_close_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="900" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_enter.xml b/core/res/res/anim-sw720dp/task_open_enter.xml
index 54a2d93..d583b6e 100644
--- a/core/res/res/anim-sw720dp/task_open_enter.xml
+++ b/core/res/res/anim-sw720dp/task_open_enter.xml
@@ -23,21 +23,20 @@
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:startOffset="500"
+            android:duration="400"/>
 
-    <translate android:fromYDelta="140%" android:toYDelta="0"
+    <translate android:fromYDelta="50%" android:toYDelta="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:startOffset="150"
-            android:duration="350"/>
+            android:interpolator="@interpolator/decelerate_quint"
+            android:startOffset="500"
+            android:duration="400" />
 
-    <scale android:fromXScale=".6" android:toXScale="1.0"
-            android:fromYScale=".6" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <scale android:fromXScale=".8" android:toXScale="1.0"
+            android:fromYScale=".8" android:toYScale="1.0"
+            android:pivotX="50%p" android:pivotY="100%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="150"
-            android:duration="350" />
-
+            android:startOffset="500"
+            android:duration="400" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_exit.xml b/core/res/res/anim-sw720dp/task_open_exit.xml
index 18e6550b..dd25a0c 100644
--- a/core/res/res/anim-sw720dp/task_open_exit.xml
+++ b/core/res/res/anim-sw720dp/task_open_exit.xml
@@ -19,25 +19,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/accelerate_quad"
             android:duration="350"/>
 
-    <translate android:fromYDelta="0" android:toYDelta="-140%"
+    <translate android:fromYDelta="0" android:toYDelta="-50%"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
+            android:interpolator="@interpolator/accelerate_cubic"
             android:duration="350"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="0.6"
-            android:fromYScale="1.0" android:toYScale="0.6"
+    <scale android:fromXScale="1.0" android:toXScale="0.8"
+            android:fromYScale="1.0" android:toYScale="0.8"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_cubic"
+            android:pivotX="50%p" android:pivotY="0%p"
+            android:interpolator="@interpolator/accelerate_quad"
             android:duration="350" />
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="500" />
+            android:duration="900" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index ee7ab60..12a1bdf 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -21,5 +21,5 @@
         android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:duration="300"/>
+            android:duration="375"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 905743e..b0f97d1 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -20,13 +20,13 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false" android:zAdjustment="top">
         <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-                android:interpolator="@interpolator/linear"
+                android:interpolator="@interpolator/accelerate_decelerate"
                 android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
                 android:duration="200" />
-        <scale android:fromXScale="1.0" android:toXScale="0.4"
-                android:fromYScale="1.0" android:toYScale="0.4"
+        <scale android:fromXScale="1.0" android:toXScale="0.5"
+                android:fromYScale="1.0" android:toYScale="0.5"
                 android:pivotX="50%p" android:pivotY="50%p"
                 android:interpolator="@interpolator/decelerate_quad"
                 android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-                android:duration="250" />
+                android:duration="375" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
new file mode 100644
index 0000000..e591a7b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/activity_picker_bg_activated.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
new file mode 100644
index 0000000..ea27290d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/activity_picker_bg_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_settings_language.png b/core/res/res/drawable-hdpi/ic_settings_language.png
new file mode 100755
index 0000000..f635b2e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_settings_language.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
index 2fc475b..9c5147e 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
index 5adecf1..9c5147e 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
index 457fa84..a257e26 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
index c3cfc29..a257e26 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
index d0e1806..dd999d6 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
index c30506d..dd999d6 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index 9106687..ea54380 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index 2bdda56..ea54380 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-large-nodpi/default_wallpaper.jpg b/core/res/res/drawable-large-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 355286e..0000000
--- a/core/res/res/drawable-large-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
new file mode 100644
index 0000000..7dfea4c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/activity_picker_bg_activated.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
new file mode 100644
index 0000000..99b0279
--- /dev/null
+++ b/core/res/res/drawable-mdpi/activity_picker_bg_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_settings_language.png b/core/res/res/drawable-mdpi/ic_settings_language.png
new file mode 100644
index 0000000..f8aca67
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_settings_language.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
index 0787d16..3d7c236 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
index 0157e68..3d7c236 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
index 51b14d0..82f05d6 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
index d68568a..82f05d6 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
index 6bf153a..9bc7a68 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
index 0d98983..9bc7a68 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 3cee7b8..670dc2e 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 43a7c4c..670dc2e 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.jpg b/core/res/res/drawable-nodpi/default_wallpaper.jpg
index 7e92243..d7475b4c 100644
--- a/core/res/res/drawable-nodpi/default_wallpaper.jpg
+++ b/core/res/res/drawable-nodpi/default_wallpaper.jpg
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index f46c6c6..63b53b8 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo_alt.png b/core/res/res/drawable-nodpi/platlogo_alt.png
index 63b53b8..f46c6c6 100644
--- a/core/res/res/drawable-nodpi/platlogo_alt.png
+++ b/core/res/res/drawable-nodpi/platlogo_alt.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
new file mode 100644
index 0000000..03a14c0
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
new file mode 100644
index 0000000..543d118
--- /dev/null
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
new file mode 100644
index 0000000..f01a79e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/activity_picker_bg_activated.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png b/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
new file mode 100644
index 0000000..7bea197
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/activity_picker_bg_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/default_wallpaper.jpg b/core/res/res/drawable-xhdpi/default_wallpaper.jpg
new file mode 100644
index 0000000..5b8d1d5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/default_wallpaper.jpg
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_settings_language.png b/core/res/res/drawable-xhdpi/ic_settings_language.png
new file mode 100644
index 0000000..2c42db3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_settings_language.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
index a0e6b20..ca48bd8 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
index 88235fe..ca48bd8 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
index 04fb9a1..c3d80f0 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
index 06a14f3..c3d80f0 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
index af7d631..df236df 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
index d6ab3ea..df236df 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 5a8e807..4acb32b 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 392f3dc..4acb32b 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-nodpi/default_wallpaper.jpg b/core/res/res/drawable-xlarge-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 355286e..0000000
--- a/core/res/res/drawable-xlarge-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/activity_picker_bg.xml b/core/res/res/drawable/activity_picker_bg.xml
new file mode 100644
index 0000000..a471c94
--- /dev/null
+++ b/core/res/res/drawable/activity_picker_bg.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:drawable="@color/transparent" />
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/list_selector_disabled_holo_light" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/activity_picker_bg_focused" />
+    <item android:state_activated="true"                                                             android:drawable="@drawable/activity_picker_bg_activated" />
+    <item android:drawable="@color/transparent" />
+
+</selector>
diff --git a/core/res/res/drawable/switch_track_holo_dark.xml b/core/res/res/drawable/switch_track_holo_dark.xml
index c9a940d..5f796c1 100644
--- a/core/res/res/drawable/switch_track_holo_dark.xml
+++ b/core/res/res/drawable/switch_track_holo_dark.xml
@@ -15,7 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_dark" />
     <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_dark" />
     <item                               android:drawable="@drawable/switch_bg_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/switch_track_holo_light.xml b/core/res/res/drawable/switch_track_holo_light.xml
index 98e53b5..39bee37 100644
--- a/core/res/res/drawable/switch_track_holo_light.xml
+++ b/core/res/res/drawable/switch_track_holo_light.xml
@@ -15,7 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_light" />
     <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_light" />
     <item                               android:drawable="@drawable/switch_bg_holo_light" />
 </selector>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
index ff65c61..8d5d404 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml
@@ -35,18 +35,6 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="24dip">
 
-            <!-- Music transport control underneath -->
-            <include android:id="@+id/transport"
-                layout="@layout/keyguard_transport_control"
-                android:layout_row="0"
-                android:layout_column="0"
-                android:layout_rowSpan="3"
-                android:layout_columnSpan="1"
-                android:layout_gravity="fill"
-                android:layout_width="match_parent"
-                android:layout_height="512dip"
-                />
-
             <!-- Status -->
             <include layout="@layout/keyguard_screen_status_land"
                 android:layout_width="match_parent"
@@ -58,6 +46,18 @@
                 android:layout_alignParentTop="true"
                 android:layout_alignParentLeft="true"/>
 
+            <!-- Music transport control -->
+            <include android:id="@+id/transport"
+                layout="@layout/keyguard_transport_control"
+                android:layout_row="0"
+                android:layout_column="0"
+                android:layout_rowSpan="3"
+                android:layout_columnSpan="1"
+                android:layout_gravity="fill"
+                android:layout_width="match_parent"
+                android:layout_height="512dip"
+                />
+
         </RelativeLayout>
 
     </RelativeLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
index 60401c9..95c15e5 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml
@@ -25,7 +25,7 @@
     <!-- top: status and emergency/forgot pattern buttons -->
     <RelativeLayout
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.40"
         android:layout_width="match_parent"
         android:gravity="center">
 
@@ -34,6 +34,16 @@
             android:layout_height="wrap_content"
             android:gravity="center">
 
+            <!-- Status -->
+            <include layout="@layout/keyguard_screen_status_port"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_marginRight="64dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
             <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
@@ -46,16 +56,6 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_port"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="100dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
@@ -64,7 +64,7 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.60"
         android:gravity="center">
 
         <LinearLayout
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
index efd406d..a666077 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
@@ -40,6 +40,15 @@
             android:layout_height="wrap_content"
             android:gravity="center">
 
+            <!-- Status -->
+            <include layout="@layout/keyguard_screen_status_port"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
             <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
@@ -52,16 +61,6 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_port"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="100dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
index de64a51..17a3c84 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
@@ -38,7 +38,17 @@
             android:layout_width="512dip"
             android:layout_height="wrap_content">
 
-            <!-- Music transport control underneath -->
+            <!-- Status -->
+            <include layout="@layout/keyguard_screen_status_land"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_marginRight="64dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
+            <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
                 android:layout_row="0"
@@ -50,16 +60,6 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_land"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="82dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
index 68499f4..0153a2e 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
@@ -39,7 +39,18 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="24dip">
 
-            <!-- Music transport control underneath -->
+            <!-- Status -->
+            <include layout="@layout/keyguard_screen_status_land"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_marginBottom="50dip"
+                android:layout_marginRight="64dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
+            <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
                 android:layout_row="0"
@@ -51,16 +62,6 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_land"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="50dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
index 086757d..78a01dd 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
@@ -26,7 +26,7 @@
     <!-- top: status -->
     <RelativeLayout
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.40"
         android:layout_width="match_parent"
         android:gravity="center">
 
@@ -35,6 +35,17 @@
             android:layout_height="wrap_content"
             android:gravity="center">
 
+            <!-- Status -->
+            <include layout="@layout/keyguard_screen_status_land"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_marginBottom="100dip"
+                android:layout_marginRight="64dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
             <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
@@ -47,23 +58,13 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_land"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="100dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
 
     <!-- bottom: lock pattern, emergency dialer and forgot pattern button -->
     <RelativeLayout
-        android:layout_weight="1"
+        android:layout_weight="0.60"
         android:layout_width="match_parent"
         android:layout_height="0dip"
         android:gravity="center">
@@ -77,7 +78,6 @@
             <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
                 android:layout_width="354dip"
                 android:layout_height="354dip"
-                android:layout_marginTop="50dip"
             />
 
             <!-- Emergency and forgot pattern buttons. -->
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 35b8665..c235289 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -173,12 +173,11 @@
     <RelativeLayout
         android:id="@+id/faceLockAreaView"
         android:visibility="invisible"
-        android:layout_row="3"
+        android:layout_row="4"
         android:layout_column="0"
-        android:layout_rowSpan="2"
+        android:layout_rowSpan="1"
         android:layout_columnSpan="1"
         android:layout_gravity="fill"
-        android:layout_marginTop="4dip"
         android:layout_marginBottom="4dip"
         android:layout_width="0dip"
         android:layout_height="0dip"
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
index 21f2474..33cbab9 100644
--- a/core/res/res/layout/notification_action.xml
+++ b/core/res/res/layout/notification_action.xml
@@ -25,4 +25,6 @@
     android:paddingLeft="8dp"
     android:textColor="#ccc"
     android:textSize="14dp"
+    android:singleLine="true"
+    android:ellipsize="end"
     />
diff --git a/core/res/res/layout/notification_action_tombstone.xml b/core/res/res/layout/notification_action_tombstone.xml
index 6c59ded..992b37c 100644
--- a/core/res/res/layout/notification_action_tombstone.xml
+++ b/core/res/res/layout/notification_action_tombstone.xml
@@ -25,6 +25,8 @@
     android:paddingLeft="8dp"
     android:textColor="#ccc"
     android:textSize="14dp"
+    android:singleLine="true"
+    android:ellipsize="end"
     android:alpha="0.5"
     android:enabled="false"
     />
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index 3692a4d..ed680a9 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -38,14 +38,15 @@
         android:orientation="vertical"
         android:paddingLeft="12dp"
         android:paddingRight="12dp"
-        android:paddingTop="4dp"
-        android:paddingBottom="4dp"
-        android:gravity="center_vertical"
+        android:paddingTop="2dp"
+        android:paddingBottom="2dp"
+        android:gravity="top"
         >
         <LinearLayout
             android:id="@+id/line1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingTop="6dp"
             android:orientation="horizontal"
             >
             <TextView android:id="@+id/title"
@@ -85,8 +86,15 @@
             android:ellipsize="marquee"
             android:visibility="gone"
             />
+        <ProgressBar
+            android:id="@android:id/progress"
+            android:layout_width="match_parent"
+            android:layout_height="12dp"
+            android:visibility="gone"
+            style="?android:attr/progressBarStyleHorizontal"
+            />
         <TextView android:id="@+id/overflow_title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
@@ -123,21 +131,14 @@
                 />
             <ImageView android:id="@+id/right_icon"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="match_parent"
                 android:layout_gravity="center"
                 android:layout_weight="0"
-                android:scaleType="center"
+                android:scaleType="centerInside"
                 android:paddingLeft="8dp"
                 android:visibility="gone"
                 android:drawableAlpha="180"
                 />
         </LinearLayout>
-        <ProgressBar
-            android:id="@android:id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            style="?android:attr/progressBarStyleHorizontal"
-            />
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
index d50b792..f2c204f 100644
--- a/core/res/res/layout/notification_template_big_base.xml
+++ b/core/res/res/layout/notification_template_big_base.xml
@@ -38,9 +38,9 @@
         android:orientation="vertical"
         android:paddingLeft="12dp"
         android:paddingRight="12dp"
-        android:paddingTop="4dp"
-        android:paddingBottom="4dp"
-        android:gravity="center_vertical"
+        android:paddingTop="2dp"
+        android:paddingBottom="2dp"
+        android:gravity="top"
         >
         <LinearLayout
             android:layout_width="match_parent"
@@ -52,6 +52,7 @@
                 android:id="@+id/line1"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:paddingTop="6dp"
                 android:orientation="horizontal"
                 >
                 <TextView android:id="@+id/title"
@@ -126,10 +127,10 @@
                     />
                 <ImageView android:id="@+id/right_icon"
                     android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
+                    android:layout_height="match_parent"
                     android:layout_gravity="center"
                     android:layout_weight="0"
-                    android:scaleType="center"
+                    android:scaleType="centerInside"
                     android:paddingLeft="8dp"
                     android:visibility="gone"
                     android:drawableAlpha="180"
@@ -138,7 +139,7 @@
             <ProgressBar
                 android:id="@android:id/progress"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
+                android:layout_height="12dp"
                 android:visibility="gone"
                 style="?android:attr/progressBarStyleHorizontal"
                 />
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
index f98970a..077616e 100644
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ b/core/res/res/layout/notification_template_big_picture.xml
@@ -31,8 +31,32 @@
         android:layout_gravity="bottom"
         android:scaleType="centerCrop"
         />
-    <include layout="@layout/notification_template_base" 
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="6dp"
+        android:layout_marginTop="64dp"
+        android:scaleType="fitXY"
+        android:src="@drawable/title_bar_shadow"
+        />
+    <include layout="@layout/notification_template_base"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         />
+  <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="208dp"
+        android:layout_marginLeft="64dp"
+        android:layout_gravity="bottom"
+        android:background="#CC111111"
+        >
+        <include
+            layout="@layout/notification_action_list"
+            android:id="@+id/actions"
+            android:layout_marginLeft="8dp"
+            android:layout_gravity="bottom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+    </FrameLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
index 210bc13..304f2b5 100644
--- a/core/res/res/layout/notification_template_big_text.xml
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -36,9 +36,9 @@
         android:orientation="vertical"
         android:paddingLeft="12dp"
         android:paddingRight="12dp"
-        android:paddingTop="4dp"
-        android:paddingBottom="4dp"
-        android:gravity="center_vertical"
+        android:paddingTop="2dp"
+        android:paddingBottom="2dp"
+        android:gravity="top"
         >
         <LinearLayout
             android:layout_width="match_parent"
@@ -50,6 +50,7 @@
                 android:id="@+id/line1"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:paddingTop="6dp"
                 android:orientation="horizontal"
                 android:layout_gravity="top"
                 android:layout_weight="0"
@@ -92,11 +93,18 @@
                 android:layout_weight="0"
                 android:visibility="gone"
                 />
+            <ProgressBar
+                android:id="@android:id/progress"
+                android:layout_width="match_parent"
+                android:layout_height="12dp"
+                android:visibility="gone"
+                android:layout_weight="0"
+                style="?android:attr/progressBarStyleHorizontal"
+                />
             <TextView android:id="@+id/big_text"
                 android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
-                android:layout_marginTop="2dp"
                 android:layout_marginBottom="2dp"
                 android:singleLine="false"
                 android:visibility="gone"
@@ -113,7 +121,7 @@
             android:layout_weight="1"
             />
         <TextView android:id="@+id/overflow_title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
@@ -127,7 +135,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:layout_weight="1"
+            android:layout_weight="0"
             >
             <TextView android:id="@+id/text"
                 android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -151,22 +159,14 @@
                 />
             <ImageView android:id="@+id/right_icon"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="match_parent"
                 android:layout_gravity="center"
                 android:layout_weight="0"
-                android:scaleType="center"
+                android:scaleType="centerInside"
                 android:paddingLeft="8dp"
                 android:visibility="gone"
                 android:drawableAlpha="180"
                 />
         </LinearLayout>
-        <ProgressBar
-            android:id="@android:id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            android:layout_weight="0"
-            style="?android:attr/progressBarStyleHorizontal"
-            />
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
index bfa2e02..121a81c 100644
--- a/core/res/res/layout/notification_template_inbox.xml
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -38,14 +38,15 @@
         android:orientation="vertical"
         android:paddingLeft="12dp"
         android:paddingRight="12dp"
-        android:paddingTop="4dp"
-        android:paddingBottom="4dp"
-        android:gravity="center_vertical"
+        android:paddingTop="2dp"
+        android:paddingBottom="2dp"
+        android:gravity="top"
         >
         <LinearLayout
             android:id="@+id/line1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingTop="6dp"
             android:orientation="horizontal"
             android:layout_weight="0"
             >
@@ -87,14 +88,20 @@
             android:visibility="gone"
             android:layout_weight="0"
             />
+        <ProgressBar
+            android:id="@android:id/progress"
+            android:layout_width="match_parent"
+            android:layout_height="12dp"
+            android:visibility="gone"
+            android:layout_weight="0"
+            style="?android:attr/progressBarStyleHorizontal"
+            />
         <TextView android:id="@+id/inbox_text0"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:singleLine="true"
             android:ellipsize="end"
-            android:paddingTop="4dp"
-            android:paddingBottom="4dp"
             android:visibility="gone"
             android:layout_weight="1"
             />
@@ -104,8 +111,6 @@
             android:layout_height="0dp"
             android:singleLine="true"
             android:ellipsize="end"
-            android:paddingTop="4dp"
-            android:paddingBottom="4dp"
             android:visibility="gone"
             android:layout_weight="1"
             />
@@ -115,8 +120,6 @@
             android:layout_height="0dp"
             android:singleLine="true"
             android:ellipsize="end"
-            android:paddingTop="4dp"
-            android:paddingBottom="4dp"
             android:visibility="gone"
             android:layout_weight="1"
             />
@@ -126,8 +129,6 @@
             android:layout_height="0dp"
             android:singleLine="true"
             android:ellipsize="end"
-            android:paddingTop="4dp"
-            android:paddingBottom="4dp"
             android:visibility="gone"
             android:layout_weight="1"
             />
@@ -137,11 +138,37 @@
             android:layout_height="0dp"
             android:singleLine="true"
             android:ellipsize="end"
-            android:paddingTop="4dp"
-            android:paddingBottom="4dp"
             android:visibility="gone"
             android:layout_weight="1"
             />
+        <TextView android:id="@+id/inbox_text5"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:visibility="gone"
+            android:layout_weight="1"
+            />
+        <TextView android:id="@+id/inbox_text6"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:visibility="gone"
+            android:layout_weight="1"
+            />
+        <TextView android:id="@+id/inbox_more"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:visibility="gone"
+            android:layout_weight="1"
+            android:text="@android:string/ellipsis"
+            />
         <include
             layout="@layout/notification_action_list"
             android:id="@+id/actions"
@@ -150,7 +177,7 @@
             android:layout_weight="0"
             />
         <TextView android:id="@+id/overflow_title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
@@ -188,22 +215,14 @@
                 />
             <ImageView android:id="@+id/right_icon"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="match_parent"
                 android:layout_gravity="center"
                 android:layout_weight="0"
-                android:scaleType="center"
+                android:scaleType="centerInside"
                 android:paddingLeft="8dp"
                 android:visibility="gone"
                 android:drawableAlpha="180"
                 />
         </LinearLayout>
-        <ProgressBar
-            android:id="@android:id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            android:layout_weight="0"
-            style="?android:attr/progressBarStyleHorizontal"
-            />
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index abeb7ba..1d464aa 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -22,7 +22,7 @@
               android:orientation="vertical"
               android:layout_height="wrap_content"
               android:layout_width="match_parent"
-              android:background="?android:attr/activatedBackgroundIndicator"
+              android:background="@android:drawable/activity_picker_bg"
               android:padding="16dp">
 
     <!-- Extended activity info to distinguish between duplicate activity names -->
diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin
index 96fa1ec..acd7993 100644
--- a/core/res/res/raw/accessibility_gestures.bin
+++ b/core/res/res/raw/accessibility_gestures.bin
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b739835..fd32685 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -176,9 +176,9 @@
     <string name="permgrouplab_network" msgid="5808983377727109831">"Netwerkkommunikasie"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"Kry toegang tot verskeie netwerkfunksies."</string>
     <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
-    <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Toegangstoestelle en netwerke deur Bluetooth."</string>
+    <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Kry toegang tot toestelle en netwerke deur Bluetooth."</string>
     <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Kortreeks-netwerke"</string>
-    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Toegangstoestelle met kortreeks-netwerke soos NFC."</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Kry toegang tot toestelle met kortreeks-netwerke soos NFC."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Oudio-instellings"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Verander oudio-instellings."</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Affekteer battery"</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Laat die program toe om te sien watter sleutels jy druk, selfs wanneer jy met \'n ander program besig is (soos om \'n wagwoord in te voer). Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"bind aan \'n invoermetode"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n invoermetode te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"verbind aan \'n toeganklikheidsdiens"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Dit laat die houer toe om aan die top-koppelvlak van \'n toeganklikheidsdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind aan \'n teksdiens"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n teksdiens (bv SpellCheckerService) te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind aan \'n VPN-diens"</string>
@@ -561,7 +563,7 @@
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Laat die program toe om die USB-berging se inhoud te lees, wat foto\'s en media kan insluit."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Laat die program toe om die SD-kaart se inhoud te lees, wat foto\'s en media kan insluit."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"verander of vee die inhoud van jou USB-berging uit"</string>
-    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"Verander of skrap die inhoud van jou SD-kaart"</string>
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"Verander of vee die inhoud van jou SD-kaart uit"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Laat die program toe om die USB-geheue te skryf."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Laat die program toe om na die SD-kaart te skryf."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"verander/vee uit interne mediabergingsinhoud"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Maak navraag skoon"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Dien navraag in"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Stemsoektog"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand gelede"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Voor 1 maand gelede"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Stel invoermetodes op"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fisiese sleutelbord"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardeware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Begin webblaaier?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Net een keer"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 6f17bec..c8bb77e 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"ከሌላ መተግበሪያ( ልክ እንደ የይለፍ ቃል መጫን) ጋር በምትገናኝበት ጊዜ እንኳን የተጫንካቸውን ቁልፎች ለማየት ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም ቢሆን አያስፈልግም፡፡"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"በግቤት ሜተድ ጠርዝ"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ በይነገጽ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ከአንድ የተደራሽነት አገልግሎት ጋር እሰር"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ያዢው ወደ የአንድ ተደራሽነት አገልግሎት ከፍተኛ-ደረጃ በይነገጽ እንዲያስር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"ለፅሁፍ አገልግሎት አሰረ"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"ያዡ ግቤት ለከፍተኛ-ደረጃ የፅሁፍ አገልግሎት ገፅታ ለመጠረዝ ይፈቅዳል። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"ለVPN አገልግሎት ተገዛ"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"የግቤት ስልቶችን አዘጋጅ"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
     <string name="hardware" msgid="7517821086888990278">"ሃርድዌር"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ማሰሺያን አስነሳ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"አንዴ ብቻ"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index dca63c3..7798b0a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"للسماح للتطبيقات بمراقبة الأحرف التي تضغط عليها حتى عند التفاعل مع تطبيق آخر (مثل إدخال كلمة مرور). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"الالتزام بطريقة إرسال ما"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لأسلوب الإدخال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"الالتزام بخدمة إمكانية الدخول"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إمكانية الدخول. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"الالتزام بخدمة إدخال النصوص"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إدخال النصوص (على سبيل المثال، SpellCheckerService). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"الالتزام بخدمة VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"محو طلب البحث"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"إرسال طلب البحث"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"البحث الصوتي"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"قبل شهر واحد"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل شهر واحد"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"إعداد أسلوب الإدخال"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"لوحة مفاتيح فعلية"</string>
     <string name="hardware" msgid="7517821086888990278">"أجهزة"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"تشغيل المتصفح؟"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"مرة واحدة فقط"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a95541e..4068610 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Дазваляе прыкладанням адсочваць клавішы, якія вы націскаеце, нават падчас узаемадзеяння з іншым прыкладаннем (напрыклад, пры ўводзе пароля). Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"звязацца з метадам уводу"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню метада ўводу. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прывязацца да службы доступу"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы доступу. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"звязаць з тэкставай службай"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"звязвацца з VPN сэрвісам"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Выдаліць запыт"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Адправіць запыт"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Галасавы пошук"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц таму"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раней, чым 1 месяц таму"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Наладзіць метады ўводу"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Фізічная клавіятура"</string>
     <string name="hardware" msgid="7517821086888990278">"Апар. ср."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Толькі адзін раз"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6ebe576..086d33a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Разрешава на приложенията да наблюдават кои клавиши натискате дори и когато взаимодействате с друго приложение (например когато въвеждате парола). Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"обвързване с метод на въвеждане"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на метод на въвеждане. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"обвързване с услуга за достъпност"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за достъпност. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"обвързване с текстова услуга"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на текстова услуга (напр. SpellCheckerService). Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"обвързване с услуга за VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Изчистване на заявката"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Изпращане на заявката"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Гласово търсене"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Преди 1 месец"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Преди повече от месец"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Методи на въвеждане: Настройка"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Физическа клавиатура"</string>
     <string name="hardware" msgid="7517821086888990278">"Хардуер"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Да се стартира ли браузърът?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Само веднъж"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5766f15f..97876f6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permet que les aplicacions facin un seguiment de les tecles que prems, fins i tot quan s\'interactua amb una altra aplicació (com ara introduir una contrasenya). No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un mètode d\'entrada"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet que el titular vinculi a la interfície de nivell superior d\'un mètode d\'entrada. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular amb un servei d\'accessibilitat"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet vincular amb la interfície de nivell superior d\'un servei d\'accessibilitat. Les aplicacions normals no haurien de necessitar-ho."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincula a un servei de text"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet al titular vincular amb la interfície de nivell superior d\'un servei de text (per exemple, SpellCheckerService). Les aplicacions normals mai no ho haurien de necessitar."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincula a un servei de VPN"</string>
@@ -529,15 +531,15 @@
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permetre la recepció de multidifusió Wi-fi"</string>
     <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Permet que l\'aplicació rebi paquets que no estiguin adreçats directament al teu dispositiu. Pot ser útil en detectar els serveis que s\'ofereixen a prop. Consumeix més energia que el mode que no utilitza la multidestinació."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"accés a la configuració de Bluetooth"</string>
-    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que cerqui i emparelli dispositius remots."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que cerqui i emparelli dispositius remots."</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
     <string name="permlab_accessWimaxState" msgid="7436749103151096452">"Visualització de les connexions WiMAX"</string>
     <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Permet que l\'aplicació visualitzi la informació sobre l\'estat de WiMAX."</string>
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
     <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Permet que l\'aplicació es connecti i es desconnecti de la xarxa WiMAX."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronització amb dispositius Bluetooth"</string>
-    <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permet que l\'aplicació mostri la configuració de la tauleta Bluetooth local i que estableixi i accepti connexions amb dispositius emparellats."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permet que una aplicació visualitzi la configuració del telèfon Bluetooth local i que estableixi i accepti connexions amb els dispositius emparellats."</string>
+    <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permet que l\'aplicació mostri la configuració de la tauleta Bluetooth local i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permet que una aplicació visualitzi la configuració del telèfon Bluetooth local i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet que l\'aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivació del bloqueig de pantalla"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Neteja la consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Envia la consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Cerca per veu"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Fa 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fa menys d\'1 mes"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configura els mètodes d\'entrada"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclat físic"</string>
     <string name="hardware" msgid="7517821086888990278">"Maquinari"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vols iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Només una vegada"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fb8f466..acd4bba 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -125,7 +125,7 @@
     <string name="httpErrorFile" msgid="2170788515052558676">"Do souboru nelze získat přístup."</string>
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Požadovaný soubor nelze najít."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Je zpracováváno příliš mnoho požadavků. Opakujte akci později."</string>
-    <string name="notification_title" msgid="8967710025036163822">"Chyba přihlášení do účtu <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <string name="notification_title" msgid="8967710025036163822">"Chyba přihlášení k účtu <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Synchronizace"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizace"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Umožňuje aplikaci sledovat, které klávesy stisknete, a to i při interakci s jinou aplikací (např. zadávání hesla). Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vazba k metodě zadávání dat"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"navázat se na službu usnadnění přístupu"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby usnadnění přístupu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"navázat se na textovou službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteli připojit se k nejvyšší úrovni rozhraní textové služby (např. SpellCheckerService). Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"navázat se na službu VPN"</string>
@@ -730,7 +732,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Zkusit znovu"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Zkusit znovu"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Překročili jste maximální povolený počet pokusů o odemknutí obličejem."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Nabíjení, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Nabíjení - <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"nabito"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Připojte dobíjecí zařízení."</string>
@@ -853,15 +855,21 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Smazat dotaz"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Odeslat dotaz"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Hlasové vyhledávání"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
   <plurals name="num_seconds_ago">
     <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
-    <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+    <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
   <plurals name="num_minutes_ago">
     <item quantity="one" msgid="3306787433088810191">"před 1 minutou"</item>
-    <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+    <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
   </plurals>
   <plurals name="num_hours_ago">
     <item quantity="one" msgid="9150797944610821849">"před 1 hodinou"</item>
@@ -882,7 +890,7 @@
   </plurals>
   <plurals name="in_num_minutes">
     <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
-    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
   </plurals>
   <plurals name="in_num_hours">
     <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
@@ -897,8 +905,8 @@
     <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
   <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"před 1 min."</item>
-    <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+    <item quantity="one" msgid="6361490147113871545">"před 1 min"</item>
+    <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
   </plurals>
   <plurals name="abbrev_num_hours_ago">
     <item quantity="one" msgid="4796212039724722116">"před 1 hodinou"</item>
@@ -913,8 +921,8 @@
     <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
   <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+    <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
+    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
   </plurals>
   <plurals name="abbrev_in_num_hours">
     <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
@@ -931,8 +939,8 @@
     <string name="days" msgid="4774547661021344602">"d."</string>
     <string name="hour" msgid="2126771916426189481">"hodina"</string>
     <string name="hours" msgid="894424005266852993">"hod."</string>
-    <string name="minute" msgid="9148878657703769868">"min."</string>
-    <string name="minutes" msgid="5646001005827034509">"min."</string>
+    <string name="minute" msgid="9148878657703769868">"min"</string>
+    <string name="minutes" msgid="5646001005827034509">"min"</string>
     <string name="second" msgid="3184235808021478">"s"</string>
     <string name="seconds" msgid="3161515347216589235">"s"</string>
     <string name="week" msgid="5617961537173061583">"týden"</string>
@@ -976,7 +984,7 @@
     <string name="capital_off" msgid="6815870386972805832">"O"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Dokončit akci pomocí aplikace"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto činnost."</string>
-    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Výchozí nastavení vymažete v části Nastavení systému &gt; Aplikace &gt; Stažené."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Výchozí nastavení vymažete v sekci Nastavení systému &gt; Aplikace &gt; Stažené."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Vyberte činnost"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Vyberte aplikaci pro zařízení USB"</string>
     <string name="noApplications" msgid="2991814273936504689">"Tuto činnost nemohou provádět žádné aplikace."</string>
@@ -997,7 +1005,7 @@
     <string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Měřítko"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobrazovat"</string>
-    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v části Nastavení systému &gt; Aplikace &gt; Stažené."</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému &gt; Aplikace &gt; Stažené."</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android se upgraduje..."</string>
@@ -1083,7 +1091,7 @@
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NOVÉ: "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"Poskytuje: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
-    <string name="usb_storage_activity_title" msgid="4465055157209648641">"Velkokapacitní paměťové zařízení USB"</string>
+    <string name="usb_storage_activity_title" msgid="4465055157209648641">"Velkokapacitní úložiště USB"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB připojeno"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Připojili jste se k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače do úložiště USB v zařízení Android či obráceně, klepněte na tlačítko níže."</string>
     <string name="usb_storage_message" product="default" msgid="805351000446037811">"Připojili jste se k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače na kartu SD v zařízení Android či obráceně, stiskněte tlačítko níže."</string>
@@ -1115,10 +1123,14 @@
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formátovat"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes rozhraní USB připojeno"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotykem zakážete ladění USB."</string>
-    <string name="select_input_method" msgid="4653387336791222978">"Vybrat metodu vstupu"</string>
-    <string name="configure_input_methods" msgid="9091652157722495116">"Nastavit metody vstupu"</string>
+    <string name="select_input_method" msgid="4653387336791222978">"Vybrat metodu zadávání"</string>
+    <string name="configure_input_methods" msgid="9091652157722495116">"Nastavit metody zadávání"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyzická klávesnice"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustit prohlížeč?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Pouze jednou"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4ec0197..9dc89a0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Tillader, at appen kan se de taster, som du trykker på, selv i en anden app (såsom indtastning af adgangskode). Dette bør aldrig være nødvendigt for normale apps."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"forpligt til en inputmetode"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Tillader, at brugeren kan forpligter sig til en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind dig til en tilgængelighedstjeneste"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Tillader, at brugeren binder sig til en grænseflade for en tilgængelighedstjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"forpligte sig til en sms-tjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Ryd forespørgslen"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Indsend forespørgslen"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Stemmesøgning"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"For 1 måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfigurer inputmetoder"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysisk tastatur"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte browseren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Kun denne ene gang"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4ca2b86..ec8ca3e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Ermöglicht der App, die von Ihnen gedrückten Tasten zu überwachen, etwa bei der Eingabe eines Passworts. Dies gilt auch für die Interaktion mit anderen Apps. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"An eine Eingabemethode binden"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"An eine Bedienungshilfe binden"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ermöglicht dem Halter, sich an die Oberfläche einer Bedienungshilfe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"An einen Textdienst binden"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ermöglicht dem Halter, sich an die Oberfläche eines Textdienstes auf oberster Ebene zu binden, z. B. eines Rechtschreibprüfungsdienstes. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"An einen VPN-Dienst binden"</string>
@@ -409,10 +411,10 @@
     <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Ermöglicht der App, auf zusätzliche Standortanbieterbefehle zuzugreifen. Schädliche Apps können so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Berechtigung zur Installation eines Standortanbieters"</string>
     <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Erstellt simulierte Standortquellen für Testzwecke. Schädliche Apps können so den von echten Standortquellen wie GPS oder Netzwerkanbietern zurückgegebenen Standort und/oder Status überschreiben oder Ihren Standort überwachen und an eine externe Quelle weitergeben."</string>
-    <string name="permlab_accessFineLocation" msgid="8116127007541369477">"genauer (GPS-) Standort"</string>
+    <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Genauer (GPS-) Standort"</string>
     <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Ermöglicht Zugriff auf genaue Standortquellen wie GPS auf dem Tablet (falls verfügbar). Schädliche Apps können damit bestimmen, wo Sie sich befinden, und so Ihren Akku zusätzlich belasten."</string>
     <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Ermöglicht Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Apps können damit bestimmen, wo Sie sich befinden, und so Ihren Akku zusätzlich belasten."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ungefährer (netzwerkbasierter) Standort"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Ungefährer (netzwerkbasierter) Standort"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Ermöglicht Zugriff auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes, um falls möglich den ungefähren Standort des Tablets zu bestimmen. Schädliche Apps können so herausfinden, wo Sie sich ungefähr befinden."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Ermöglicht Zugriff auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Apps können so herauszufinden, wo Sie sich ungefähr befinden."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
@@ -548,9 +550,9 @@
     <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Ermöglicht der App, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für die App \"Personen\" aktiviert ist oder nicht"</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
     <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Ermöglicht der App, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen"</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abonnierte Feeds lesen"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Abonnierte Feeds lesen"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ermöglicht der App, Details zu den zurzeit synchronisierten Feeds abzurufen"</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abonnierte Feeds schreiben"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"Abonnierte Feeds schreiben"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Ermöglicht der App, Änderungen an kürzlich synchronisierten Feeds vorzunehmen. Schädliche Apps können so Ihre synchronisierten Feeds ändern."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"Begriffe lesen, die Sie zum Wörterbuch hinzugefügt haben"</string>
     <string name="permdesc_readDictionary" msgid="8977815988329283705">"Ermöglicht der App, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Anfrage löschen"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Anfrage senden"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Sprachsuche"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Eingabemethoden einrichten"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Physische Tastatur"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
@@ -1193,7 +1205,7 @@
     <string name="throttled_notification_title" msgid="6269541897729781332">"Mobildatenlimit überschritten"</string>
     <string name="throttled_notification_message" msgid="5443457321354907181">"Durch Berühren weitere Informationen zum Mobildatenverbrauch aufrufen"</string>
     <string name="no_matches" msgid="8129421908915840737">"Keine Treffer"</string>
-    <string name="find_on_page" msgid="1946799233822820384">"Suchen"</string>
+    <string name="find_on_page" msgid="1946799233822820384">"Auf Seite suchen"</string>
   <plurals name="matches_found">
     <item quantity="one" msgid="8167147081136579439">"1 Treffer"</item>
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> von <xliff:g id="TOTAL">%d</xliff:g>"</item>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Nur einmal"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 08e2389..c44f789 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Επιτρέπει στην εφαρμογή να παρακολουθεί τα πλήκτρα που πατάτε, ακόμη και σε μια άλλη εφαρμογή (όπως π.χ. η καταχώρηση ενός κωδικού πρόσβασης). Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"δέσμευση σε μέθοδο εισόδου"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"δέσμευση σε υπηρεσία προσβασιμότητας"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανώτατου επιπέδου μιας υπηρεσίας προσβασιμότητας. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Επιτρέπει στον κάτοχο τη σύνδεση με τη διεπαφή ανωτέρου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων (π.χ. SpellCheckerService). Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"δέσμευση σε υπηρεσία VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Απαλοιφή ερωτήματος"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Υποβολή ερωτήματος"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Φωνητική αναζήτηση"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Ρύθμιση μεθόδων εισαγωγής"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Φυσικό πληκτρολόγιο"</string>
     <string name="hardware" msgid="7517821086888990278">"Υλικό"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Μόνο μία φορά"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c991437..a54c479 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Allows the app to watch the keys that you press even when interacting with another app (such as typing a password). Should never be needed for normal apps."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"bind to an input method"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Allows the holder to bind to the top-level interface of an input method. Should never be needed for normal apps."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind to an accessibility service"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Allows the holder to bind to the top-level interface of an accessibility service. Should never be needed for normal apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind to a text service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Allows the holder to bind to the top-level interface of a text service (e.g. SpellCheckerService). Should never be needed for normal applications."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind to a VPN service"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Clear query"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Submit query"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Voice search"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Set up input methods"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Physical keyboard"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Just Once"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0da38aa..64429e9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que la aplicación observe las teclas que presionas, incluso al interactuar con otra aplicación (como cuando escribes una contraseña). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un método de entrada"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a un servicio de accesibilidad"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de texto (p. ej., SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular con un servicio de VPN"</string>
@@ -731,7 +733,7 @@
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Volver a intentarlo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="4938930459620989972">"Cargada."</string>
+    <string name="lockscreen_charged" msgid="4938930459620989972">"Cargado."</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Eliminar la consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
   <plurals name="num_seconds_ago">
@@ -1081,7 +1089,7 @@
     <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Listo"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NUEVO: "</font></string>
-    <string name="perms_description_app" msgid="5139836143293299417">"Proporcionado por <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <string name="perms_description_app" msgid="5139836143293299417">"Proporcionado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"Almacenamiento USB masivo"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"Conectado al USB"</string>
@@ -1115,10 +1123,14 @@
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración de USB conectada"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración de USB."</string>
-    <string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de introducción"</string>
+    <string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de entrada"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1311,7 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"Enviando..."</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Solo una vez"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ea1f3c4..f5ffece 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que la aplicación sepa las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). Nunca debería ser necesario para las aplicaciones normales."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"enlazar con un método de introducción de texto"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que se enlace con la interfaz de nivel superior de un método de introducción de texto. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"enlazar con un servicio de accesibilidad"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite enlazar con la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"enlazar con un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite enlazar con la interfaz de nivel superior de un servicio de texto (por ejemplo, SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"enlazar con un servicio VPN"</string>
@@ -673,7 +675,7 @@
     <string name="postalTypeHome" msgid="8165756977184483097">"Casa"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Trabajo"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Otro"</string>
-    <string name="imTypeCustom" msgid="2074028755527826046">"Personalizada"</string>
+    <string name="imTypeCustom" msgid="2074028755527826046">"Personalizado"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"Casa"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Trabajo"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Otro"</string>
@@ -727,8 +729,8 @@
     <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Volver a llamada"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
-    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Volver a intentar"</string>
-    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Volver a intentar"</string>
+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo"</string>
+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Vuelve a intentarlo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"Cargado"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Borrar consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
   <plurals name="num_seconds_ago">
@@ -925,7 +933,7 @@
     <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
   </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
-    <string name="preposition_for_time" msgid="5506831244263083793">"a la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
     <string name="day" msgid="8144195776058119424">"día"</string>
     <string name="days" msgid="4774547661021344602">"días"</string>
@@ -1085,13 +1093,13 @@
     <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"Almacenamiento USB masivo"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"Conexión por USB"</string>
-    <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Has conectado el dispositivo al ordenador por USB. Toca el siguiente botón si quieres copiar archivos entre el ordenador y el almacenamiento USB del dispositivo."</string>
-    <string name="usb_storage_message" product="default" msgid="805351000446037811">"Has conectado el dispositivo al ordenador por USB. Toca el siguiente botón si quieres copiar archivos entre el ordenador y la tarjeta SD del dispositivo."</string>
+    <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Has conectado el dispositivo al ordenador por USB. Toca el siguiente botón si quieres transferir archivos entre el ordenador y el almacenamiento USB del dispositivo."</string>
+    <string name="usb_storage_message" product="default" msgid="805351000446037811">"Has conectado el dispositivo al ordenador por USB. Toca el siguiente botón si quieres transferir archivos entre el ordenador y la tarjeta SD del dispositivo."</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar almacenamiento USB"</string>
     <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Se ha producido un error al usar el almacenamiento USB como almacenamiento USB masivo."</string>
     <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Se ha producido un error al usar la tarjeta SD para el almacenamiento USB masivo."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"Conexión por USB"</string>
-    <string name="usb_storage_notification_message" msgid="939822783828183763">"Toca para copiar archivos en el ordenador o del mismo."</string>
+    <string name="usb_storage_notification_message" msgid="939822783828183763">"Toca para transferir archivos"</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar almacenamiento USB"</string>
     <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Toca para desactivar el almacenamiento USB."</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"El almacenamiento USB está en uso"</string>
@@ -1103,7 +1111,7 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si activas el almacenamiento USB, se detendrán algunas aplicaciones que estás usando y es posible que no estén disponibles hasta que lo desactives."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Error de funcionamiento de USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como un dispositivo multimedia"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como disp. multimedia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
@@ -1113,12 +1121,16 @@
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Se borrarán todos los archivos almacenados en el almacenamiento USB. Esta acción no se puede deshacer."</string>
     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Se perderán todos los datos de tu tarjeta."</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
-    <string name="adb_active_notification_title" msgid="6729044778949189918">"Dispositivo de depuración USB conectado"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"Tocar para inhabilitar la depuración USB"</string>
-    <string name="select_input_method" msgid="4653387336791222978">"Seleccionar método de introducción"</string>
-    <string name="configure_input_methods" msgid="9091652157722495116">"Ajustar métodos de introducción"</string>
+    <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para inhabilitar la depuración USB"</string>
+    <string name="select_input_method" msgid="4653387336791222978">"Selecciona un método de introducción"</string>
+    <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1303,7 +1315,7 @@
     <string name="fingerprints" msgid="4516019619850763049">"Huellas digitales:"</string>
     <string name="sha256_fingerprint" msgid="4391271286477279263">"Huella digital SHA-256:"</string>
     <string name="sha1_fingerprint" msgid="7930330235269404581">"Huella digital SHA-1:"</string>
-    <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Ver todas"</string>
+    <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Ver todo"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Seleccionar actividad"</string>
     <string name="share_action_provider_share_with" msgid="5247684435979149216">"Compartir con"</string>
     <string name="status_bar_device_locked" msgid="3092703448690669768">"Dispositivo bloqueado"</string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Solo una vez"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 88f8fdb..ea57cf5 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Võimaldab rakendusel vaadata vajutatavaid klahve, isegi kui suhtlete teise rakendusega (näiteks parooli sisestamisel). Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"seo sisestusmeetodiga"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lubab omanikul siduda sisestusmeetodi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sidumine juurdepääsuteenusega"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lubab omanikul luua sideme juurdepääsuteenuseteenuse ülataseme liidesega. Tavarakenduste puhul ei tohiks seda kunagi vaja minna."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tekstiteenusega sidumine"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"seo VPN-teenusega"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Tühjenda päring"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Päringu esitamine"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Häälotsing"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 kuu tagasi"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Varem kui 1 kuu tagasi"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Seadista sisestusmeetodid"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Füüsiline klaviatuur"</string>
     <string name="hardware" msgid="7517821086888990278">"Riistvara"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Ainult üks kord"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 26b5e77..393ba0c 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"به برنامه اجازه می‎دهد تا کلیدهایی را که هنگام تعامل با برنامه دیگر فشار می‎دهید ببیند (مانند تایپ کردن گذرواژه). برای برنامه‎های عادی مورد نیاز نیست."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"پیوند شده به روش ورودی"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"به دارنده این دستگاه اجازه می‎دهد تا به رابط سطح بالای یک روش ورودی متصل شود. این ویژگی هیچگاه برای برنامه‎های معمولی ضروری نمی‎باشد."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"اتصال به سرویس دسترسی"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس دسترسی متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"اتصال به یک سرویس متنی"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"به دارنده اجازه می‌دهد خود را به یک رابط سطح بالای خدمات متنی مرتبط کند (برای مثال SpellCheckerService). هرگز برای برنامه‌های عادی لازم نیست."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"اتصال به یک سرویس VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"پاک کردن عبارت جستجو"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ارسال عبارت جستجو"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"جستجوی صوتی"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ماه قبل"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل از 1 ماه گذشته"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"تنظیم روش‌های ورودی"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"صفحه کلید فیزیکی"</string>
     <string name="hardware" msgid="7517821086888990278">"سخت‌افزار"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"مرورگر راه‌اندازی شود؟"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"تماس را می‌پذیرید؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"فقط یکبار"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3d6d5b0..9e0e8e6 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Antaa sovelluksen lukea näppäinpainalluksia myös käytettäessä muita sovelluksia (esimerkiksi kirjoitettaessa salasanaa). Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"sitoudu syöttötapaan"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Antaa sovelluksen sitoutua syötetavan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sitoudu esteettömyyspalveluun"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Antaa sovelluksen sitoutua esteettömyyspalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tekstipalveluun sitoutuminen"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Antaa sovelluksen sitoutua tekstipalvelun (kuten SpellCheckerServicen) ylätason liittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"sitoudu VPN-palveluun"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Tyhjennä kysely"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Lähetä kysely"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Puhehaku"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Määritä syöttötavat"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyysinen näppäimistö"</string>
     <string name="hardware" msgid="7517821086888990278">"Laitteisto"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Käynnistetäänkö selain?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Vain kerran"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 9a8778e..f757e27 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -145,7 +145,7 @@
     <string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
-    <string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre le téléphone ?"</string>
+    <string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil ?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"Voulez-vous redémarrer en mode sans échec ? Cette opération aura pour effet de désactiver toutes les applications tierces que vous avez installées. Elles seront réactivées au prochain redémarrage."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Récentes"</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permet à l\'application d\'identifier les touches sur lesquelles vous appuyez, même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"Association à un mode de saisie"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un mode de saisie. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"associer à un service d\'accessibilité"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service d\'accessibilité. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"associer à un service de texte"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet à l\'application de s\'associer à l\'interface de haut niveau d\'un service de texte (par exemple, SpellCheckerService). Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"associer à un service VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Effacer la requête"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Envoyer la requête"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Recherche vocale"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurer les modes de saisie"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Clavier physique"</string>
     <string name="hardware" msgid="7517821086888990278">"Matériel"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Une seule fois"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 008f93b..47656b6 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"एप्लिकेशन को अन्य एप्लिकेशन के साथ सहभागिता करते समय भी आपके द्वारा दबाई जाने वाली कुंजियां देखने देता है (जैसे कोई पासवर्ड लिखना). सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"किसी इनपुट विधि से आबद्ध करें"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्‍यता सेवा से आबद्ध करें"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्‍तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"क्‍वेरी साफ़ करें"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"क्वेरी सबमिट करें"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"ध्वनि खोज"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 माह पहले"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 माह से पहले"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"इनपुट पद्धतियां सेट करें"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"भौतिक कीबोर्ड"</string>
     <string name="hardware" msgid="7517821086888990278">"हार्डवेयर"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउज़र लॉन्च करें?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"बस एक बार"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 55f923f..98f736b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Omogućuje aplikaciji da gleda koje tipke pritiskate čak i kada radite s nekom drugom aplikacijom (na primjer, pisanje zaporke). Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vezano uz način unosa"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Nositelju omogućuje povezivanje sučelja najviše razine načina unosa. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezivanje uz uslugu dostupnosti"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge dostupnosti. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vezanje na tekstualnu uslugu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Omogućuje korisniku povezivanje s najvišom razinom sučelja tekstualne usluge (npr. SpellCheckerService). Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vezanje na VPN uslugu"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Izbriši upit"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Pošalji upit"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Glasovno pretraživanje"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prije 1 mjesec"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prije 1 mjesec"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Postavljanje načina unosa"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizička tipkovnica"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Pokrenuti preglednik?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Samo jednom"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 04ea787..239bfe4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Lehetővé teszi az alkalmazás számára, hogy figyelje a lenyomott billentyűket még másik alkalmazás használata esetén is (például jelszó beírásakor). A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"összekapcsolás egy beviteli módszerrel"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy beviteli mód legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"csatlakozás egy kisegítő szolgáltatáshoz"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lehetővé teszi a használó számára, hogy csatlakozzon egy kisegítő szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"csatlakozás szövegszolgáltatáshoz"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lehetővé teszi, hogy a tulajdonos egy szöveges szolgáltatás felső szintjéhez kapcsolódjon (pl. SpellCheckerService). A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"csatlakozás egy VPN-szolgáltatáshoz"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Lekérdezés törlése"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Lekérdezés küldése"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Hangalapú keresés"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 hónapja"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Több mint 1 hónapja"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Beviteli módok beállítása"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizikai billentyűzet"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Böngésző indítása?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Csak egyszer"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5bca912..f249c2c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Mengizinkan apl mengawasi tombol yang Anda tekan bahkan ketika berinteraksi dengan apl lain (misalnya mengetik sandi). Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"mengikat ke metode masukan"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu metode masukan. Tidak pernah diperlukan oleh apl normal."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"mengikat ke layanan aksesibilitas"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"mengikat ke layanan SMS"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan teks (mis. SpellCheckerService). Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"mengikat ke layanan VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Hapus kueri"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Mengirimkan kueri"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Penelusuran suara"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Menyiapkan metode masukan"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Keyboard fisik"</string>
     <string name="hardware" msgid="7517821086888990278">"Perangkat Keras"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Luncurkan Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Sekali Saja"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0764284..ffcf6bb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Consente all\'applicazione di conoscere i tasti premuti anche durante l\'interazione con un\'altra applicazione (ad esempio quando digiti una password). Non dovrebbe mai essere necessaria per le applicazioni normali."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"associaz. a un metodo di inserimento"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Consente l\'associazione di un metodo di inserimento all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"collegamento a un servizio di accessibilità"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di accessibilità. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"associazione a un servizio di testo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di testo (ad esempio SpellCheckerService). Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"associazione a un servizio VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Cancella query"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Invia query"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Ricerca vocale"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configura metodi di immissione"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Tastiera fisica"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Avviare l\'applicazione Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Solo una volta"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a111f5a..65cb688 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"מאפשר ליישום לצפות במקשים שאתה לוחץ עליהם בעת ביצוע פעילות עם יישום אחר (למשל, הקלדת סיסמה). הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"הכפף לשיטת קלט"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שיטת קלט. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"הכפפה לשירות נגישות"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"מתיר לבעלים להכפיף לממשק ברמה העליונה של שירות זמינות. הרשאה זו אף פעם אינה אמורה להיות נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"הכפפה לשירות טקסט"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"מאפשר למשתמש ליצור איגוד לממשק הרמה העליונה של שירות טקסט (למשל, SpellCheckerService). הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"אגד לשירות VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"נקה שאילתה"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"שלח שאילתה"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"חיפוש קולי"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"לפני חודש אחד"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"לפני חודש אחד"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"הגדר שיטות קלט"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"מקלדת פיזית"</string>
     <string name="hardware" msgid="7517821086888990278">"חומרה"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"להפעיל את הדפדפן?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"רק פעם אחת"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7e3e95b..176a6b5 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"別のアプリとの対話操作(パスワード入力など)の場合でもキー入力を監視することをアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"入力方法に関連付ける"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"入力方法のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ユーザー補助サービスにバインド"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ユーザー補助サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"テキストサービスにバインド"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"テキストサービス(SpellCheckerServiceなど)のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPNサービスにバインド"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"検索キーワードを削除"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"検索キーワードを送信"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"音声検索"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1か月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1か月前"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"入力方法をセットアップ"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"物理キーボード"</string>
     <string name="hardware" msgid="7517821086888990278">"ハードウェア"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ブラウザを起動しますか?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"今回のみ"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 14730d95..03de346 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"앱이 다른 앱과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"입력 방법 연결"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"권한을 가진 프로그램이 입력 방법에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"접근성 서비스와 연결"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"권한을 가진 프로그램이 접근성 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"텍스트 서비스 연결"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"권한을 가진 프로그램이 텍스트 서비스(예: SpellCheckerService)에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN 서비스와 연결"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"검색어 삭제"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"검색어 보내기"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"음성 검색"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"입력 방법 설정"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"물리적 키보드"</string>
     <string name="hardware" msgid="7517821086888990278">"하드웨어"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"브라우저를 실행하시겠습니까?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"한 번만"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3c705ec..0474391 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Leidžiama programai stebėti paspaudžiamus klavišus, net kai sąveikaujama su kita programa (pvz., įvedant slaptažodį). Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"susaistyti įvesties būdą"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Leidžiama savininką susaistyti su įvesties metodo aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"susisaistyti su pasiekiamumo paslauga"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Savininkui leidžiama susisaistyti su aukščiausio lygio pasiekiamumo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"priskirti teksto paslaugą"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Leidžiama savininkui priskirti aukščiausio lygio teksto paslaugos (pvz., „SpellCheckerService“) sąsają. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"susaistyti su VPN paslauga"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Išvalyti užklausą"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Patvirtinti užklausą"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Paieška balsu"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prieš 1 mėn."</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prieš maždaug 1 mėnesį"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Nustatyti įvesties metodus"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizinė klaviatūra"</string>
     <string name="hardware" msgid="7517821086888990278">"Apar. įr."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
@@ -1311,7 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"Siunčiama…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Tik kartą"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0b96365..aaed6e2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Ļauj lietotnei skatīt taustiņus, ko nospiežat, pat ja darbojaties citā lietotnē (piemēram, ievadot paroli). Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"saistīt ar ievades metodi"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ļauj īpašniekam izveidot saiti ar ievades metodes augstākā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"saistīt ar pieejamības pakalpojumu"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ļauj īpašniekam izveidot saiti ar pieejamības pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm šī atļauja nav nepieciešama."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"saistīt ar īsziņu pakalpojumu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ļauj īpašniekam veikt saistīšanu ar īsziņu pakalpojuma augstākā līmeņa saskarni (piem., SpellCheckerService). Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"saistīt ar VPN pakalpojumu"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Notīrīt vaicājumu"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Iesniedziet vaicājumu."</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Meklēšana ar balsi"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pirms 1 mēneša"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vairāk nekā pirms 1 mēneša"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Iestatīt ievades metodes"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziskā tastatūra"</string>
     <string name="hardware" msgid="7517821086888990278">"Aparatūra"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
@@ -1311,7 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"Notiek sūtīšana…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Tikai vienreiz"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 47aa00a..fec15b2 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -177,7 +177,7 @@
     <string name="permgroupdesc_network" msgid="4478299413241861987">"Akses pelbagai ciri rangkaian."</string>
     <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Akses peranti dan rangkaian melalui Bluetooth."</string>
-    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Rangkaian jarak-pendek"</string>
+    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Rangkaian jarak-dekat"</string>
     <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Akses peranti melalui rangkaian jarak dekat seperti NFC."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Tetapan Audio"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Tukar tetapan audio."</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Membenarkan apl untuk melihat kekunci yang anda tekan walaupun semasa berinteraksi dengan apl lain (seperti menaip kata laluan). Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"terikat kepada kaedah input"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kaedah input itu. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"terikat kepada perkhidmatan yang boleh diakses"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan yang boleh diakses. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"terikat kepada perkhidmatan teks"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Membenarkan pemegang mengikat kepada antara muka peringkat atasan perkhidmatan teks(mis. PerkhidmatanPenyemakEjaan). Tidak seharusnya diperlukan untuk apl biasa."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"terikat kepada perkhidmatan VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Pertanyaan jelas"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Serah pertanyaan"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Carian suara"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Sediakan kaedah input"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Papan kekunci fizikal"</string>
     <string name="hardware" msgid="7517821086888990278">"Perkakasan"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancarkan Penyemak Imbas?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Hanya Sekali"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a0e00eb..47935fd 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Lar appen se hvilke taster du trykker på, selv når du samhandler med en annen app (f.eks. skriver inn et passord). Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binde til en inndatametode"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lar innehaveren binde det øverste nivået av grensesnittet til en inndatametode. Skal aldri være nødvendig for normale apper."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"binde seg til en tilgjengelighetstjeneste"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Gir innehaveren tillatelse til å bindes til det øverste nivået av grensesnittet for en tilgjengelighetstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"binde til en teksttjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lar innehaveren binde seg til øverste grensesnittnivå for en teksttjeneste (f.eks. SpellCheckerService). Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"binde deg til en VPN-tjeneste"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Slett søket"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Send inn spørsmål"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Talesøk"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfigurer inndatametoder"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysisk tastatur"</string>
     <string name="hardware" msgid="7517821086888990278">"Maskinvare"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte nettleseren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Bare én gang"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index dfd67ff..4ad7180 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Hiermee kan de app bijhouden op welke toetsen u drukt, zelfs wanneer u een andere app gebruikt (bijvoorbeeld wanneer u een wachtwoord typt). Dit is niet nodig voor normale apps."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"verbinden aan een invoermethode"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Hiermee kan de houder zich verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"koppelen aan een toegankelijkheidsservice"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een toegankelijkheidsservice. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"koppelen aan een sms-service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Hiermee kan de gebruiker koppelen met de hoofdinterface van een tekstservice (zoals SpellCheckerService). Dit is niet nodig voor normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"koppelen aan een VPN-service"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Zoekopdracht wissen"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Zoekopdracht verzenden"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Spraakgestuurd zoeken"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Invoermethoden instellen"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiek toetsenbord"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Oproep accepteren?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Alleen nu gebruiken"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 10effa3..a634006 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Pozwala aplikacji na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"powiązanie ze sposobem wprowadzania tekstu"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Pozwala na powiązanie wybranego sposobu wprowadzania tekstu z interfejsem najwyższego poziomu. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"tworzenie powiązania z usługą ułatwień dostępu"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi ułatwień dostępu. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tworzenie powiązania z usługą tekstową"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi tekstowej (np. SpellCheckerService). Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"tworzenie powiązania z usługą VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Wyczyść zapytanie"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Wyślij zapytanie"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Wyszukiwanie głosowe"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
   <plurals name="num_seconds_ago">
@@ -974,8 +982,8 @@
     <string name="loading" msgid="7933681260296021180">"Wczytywanie…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Wł."</string>
     <string name="capital_off" msgid="6815870386972805832">"Wył."</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Zakończ czynność korzystając z"</string>
-    <string name="alwaysUse" msgid="4583018368000610438">"Używaj domyślnie dla tej czynności."</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Zakończ czynność przez..."</string>
+    <string name="alwaysUse" msgid="4583018368000610438">"Domyślne dla tej czynności"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Wyczyść wartości domyślne w: Ustawienia systemu &gt; Aplikacje &gt; Pobrane."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Wybierz czynność"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Wybierz aplikację dla urządzenia USB"</string>
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfiguruj metody wprowadzania"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Klawiatura fizyczna"</string>
     <string name="hardware" msgid="7517821086888990278">"Sprzęt"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Tylko raz"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4bb3b2f..38ce3ac 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -178,7 +178,7 @@
     <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Aceder a dispositivos e redes através de Bluetooth."</string>
     <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Redes de Curto Alcance"</string>
-    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Aceder a dispositivos através de redes de curto alcance como NFC."</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Aceder a dispositivos através de redes de curto alcance tal como a NFC."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Definições de Áudio"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Alterar as definições de áudio."</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Afetar a Bateria"</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que a aplicação veja as teclas que o utilizador prime, mesmo ao interagir com outra aplicação (como, por exemplo, ao introduzir uma palavra-passe). Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite ao titular vincular-se à interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicações normais."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a um serviço de acessibilidade"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o titular vincule a interface de nível superior de um serviço de acessibilidade. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a um serviço de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite ao titular ligar-se à interface de nível superior de um serviço de texto (por exemplo SpellCheckerService). Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular a um serviço VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Limpar consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Pesquisa por voz"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introdução"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1311,7 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"A enviar..."</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar Navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Só Uma Vez"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4236d50..2a4855c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que o aplicativo veja as teclas pressionadas mesmo quando você estiver interagindo com outro aplicativo, como ao digitar uma senha. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que o proprietário utilize a interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicativos normais."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"usar um serviço de acessibilidade"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o proprietário use a interface de nível superior de um serviço de acessibilidade. Nunca deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"sujeitar-se a um serviço de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite que o proprietário utilize interface de nível superior de um serviço de texto (por exemplo, SpellCheckerService). Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"se ligam a um serviço de VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Limpar consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Pesquisa por voz"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
   <plurals name="num_seconds_ago">
@@ -1104,7 +1112,7 @@
     <string name="dlg_error_title" msgid="7323658469626514207">"Falha na operação do USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como um dispositivo de mídia"</string>
-    <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectadas como uma câmera"</string>
+    <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como câmera"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectados como um instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toque para obter outras opções USB."</string>
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de entrada"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Só uma vez"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index e22bb14..397b095 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -474,6 +474,10 @@
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"associar cun ina metoda d\'endataziun"</string>
     <!-- no translation found for permdesc_bindInputMethod (3250440322807286331) -->
     <skip />
+    <!-- no translation found for permlab_bindAccessibilityService (5357733942556031593) -->
+    <skip />
+    <!-- no translation found for permdesc_bindAccessibilityService (7034615928609331368) -->
+    <skip />
     <!-- no translation found for permlab_bindTextService (7358378401915287938) -->
     <skip />
     <!-- no translation found for permdesc_bindTextService (8151968910973998670) -->
@@ -1358,6 +1362,12 @@
     <skip />
     <!-- no translation found for searchview_description_voice (2453203695674994440) -->
     <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Avant 1 mais"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Avant dapli ch\'in mais"</string>
   <plurals name="num_seconds_ago">
@@ -1732,6 +1742,10 @@
     <skip />
     <!-- no translation found for hardware (7517821086888990278) -->
     <skip />
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -2071,6 +2085,6 @@
     <skip />
     <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
     <skip />
-    <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index dd639858..52fd28e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite aplicaţiei să monitorizeze tastele pe care le apăsaţi când interacţionaţi cu o altă aplicaţie (cum ar fi introducerea unei parole). Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"conectare la o metodă de intrare"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei metode de introducere. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"conectare la un serviciu de accesibilitate"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu de accesibilitate. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"conectare la un serviciu text"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite proprietarului să se conecteze la o interfaţă de nivel superior a unui serviciu text (de ex., SpellCheckerService). Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"conectare la un serviciu VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Ştergeţi interogarea"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurare metode introducere"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Tastatură fizică"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidaţi"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lansaţi browserul?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Acceptaţi apelul?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Doar o singură dată"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 899f13a..75face4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Приложение сможет отслеживать нажатие пользователем клавиш даже при работе с другими программами (например, при вводе пароля). Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"связывать с методом ввода"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Приложение сможет подключаться к базовому интерфейсу системы ввода. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"подключаться к службе спецвозможностей"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Приложение сможет подключаться к базовому интерфейсу службы специальных возможностей. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"привязка к службе текстовых сообщений"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Позволяет подключаться к базовому интерфейсу службы текстовых сообщений (например, SpellCheckerService). Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"подключаться к VPN-службе"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Удалить запрос"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Отправить запрос"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Голосовой поиск"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Настройка способов ввода"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Физическая клавиатура"</string>
     <string name="hardware" msgid="7517821086888990278">"Аппаратура"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запустить браузер?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Только сейчас"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 79cb76a..6f1c5e7 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Umožňuje aplikácii sledovať, ktoré klávesy stlačíte, dokonca aj keď pracujete s inou aplikáciou (napr. zadávanie hesla). Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"väzba na metódu vstupu"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania metódy vstupu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"viazať na službu zjednodušeného ovládania"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby zjednodušeného ovládania. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"väzba na textovú službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania textovej služby (napr. SpellCheckerService). Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"Zaviazať k službe VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Jasný dopyt"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Odoslať dopyt"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Hlasové vyhľadávanie"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"pred 1 mesiacom"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Viac ako pred 1 mesiacom"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Nastavenie metód vstupu"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyzická klávesnica"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardvér"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustiť prehliadač?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Len raz"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 32a0a22..90398a3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Programu omogoča spremljanje tipk, ki jih pritisnete med interakcijo z drugim programom (na primer vnos gesla). Navadni programi tega nikoli ne potrebujejo."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"povezovanje z načinom vnosa"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lastniku omogoča, da se poveže z vmesnikom načina vnosa najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezano na storitev za ljudi s posebnimi potrebami"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom storitve za ljudi s posebnimi potrebami najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"poveži z besedilno storitvijo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dovoljuje, da se lastnik poveže z vmesnikom besedilne storitve najvišje ravni (npr. SpellCheckerService). Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"povezava s storitvijo navideznega zasebnega omrežja"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Izbris poizvedbe"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Pošlji poizvedbo"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Glasovno iskanje"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pred 1 mesecem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Pred več kot 1 mesecem"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Nastavi načine vnosa"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizična tipkovnica"</string>
     <string name="hardware" msgid="7517821086888990278">"Strojna oprema"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Ali želite odpreti brskalnik?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Samo tokrat"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e943dda..6f067a1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -175,28 +175,20 @@
     <string name="permgroupdesc_location" msgid="5704679763124170100">"Надгледајте своју физичку локацију."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Комуникација преко мреже"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"Приступајте разним функцијама мреже."</string>
-    <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
-    <skip />
-    <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
-    <skip />
+    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+    <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Приступање уређајима и мрежама преко Bluetooth-а."</string>
+    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Мреже кратког домета"</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Приступање уређајима преко мрежа кратког домета, као што је NFC."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Аудио подешавања"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Промена аудио подешавања."</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Утицај на батерију"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Коришћење функција које могу брзо да истроше батерију."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Директан приступ календару и догађајима."</string>
-    <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
-    <skip />
-    <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
-    <skip />
+    <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Читање речника корисника"</string>
+    <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Читање речи у речнику корисника."</string>
+    <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Уписивање у речник корисника"</string>
+    <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Додавање речи у речник корисника."</string>
     <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Обележивачи и историја"</string>
     <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Директан приступ обележивачима и историји прегледача."</string>
     <string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Аларм"</string>
@@ -325,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Дозвољава апликацији да види које тастере притискате чак и док радите у некој другој апликацији (нпр. када уносите лозинку). Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"обавезивање на методу уноса"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Омогућава да се власник обавеже на интерфејс методе уноса највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"повезивање са услугом приступачности"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозвољава власнику да се повеже са интерфејсом услуге приступачности највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"обавезивање на текстуалну услугу"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Омогућава власнику да се обавеже на интерфејс текстуалне услуге највишег нивоа (нпр. SpellCheckerService). Обичне апликације никада не би требало да је користе."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"везивање за VPN услугу"</string>
@@ -569,8 +563,7 @@
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Дозвољава апликацији читање садржаја USB меморије, што могу да буду слике и медиа датотеке."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Дозвољава апликацији да чита садржај SD картице, који може да обухвата слике и медиа датотеке."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"измена или брисање садржаја USB меморије"</string>
-    <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
-    <skip />
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"мењање или брисање садржаја SD картице"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дозвољава апликацији да уписује податке на USB меморију."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозвољава апликацији да уписује податке на SD картицу."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"измена/брисање интерне меморије медија"</string>
@@ -862,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Обриши упит"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Пошаљи упит"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Гласовна претрага"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Пре месец дана"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пре месец дана"</string>
   <plurals name="num_seconds_ago">
@@ -1090,8 +1089,7 @@
     <string name="date_time_set" msgid="5777075614321087758">"Подеси"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Готово"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"НОВО: "</font></string>
-    <!-- no translation found for perms_description_app (5139836143293299417) -->
-    <skip />
+    <string name="perms_description_app" msgid="5139836143293299417">"Омогућава <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB великог капацитета"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB је повезан"</string>
@@ -1129,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Подеси методе уноса"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Физичка тастатура"</string>
     <string name="hardware" msgid="7517821086888990278">"Хардвер"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1322,6 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Желите ли да покренете прегледач?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
-    <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f91db69..c9b7e2b 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Tillåter att appen övervakar knapparna som du trycker på, till och med när du använder andra appar (till exempel när du anger ett lösenord). Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binda till en metod för indata"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind till en tillgänglighetstjänst"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en tillgänglighetstjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind till en texttjänst"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillåter innehavaren att binda mot den högsta gränssnittsnivån i en texttjänst (t.ex. SpellCheckerService). Bör aldrig behövas för normala appar."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind till en VPN-tjänst"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Ta bort frågan"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Skicka fråga"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Röstsökning"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfigurera inmatningsmetoder"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiskt tangentbord"</string>
     <string name="hardware" msgid="7517821086888990278">"Maskinvara"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vill du öppna webbläsaren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Bara den här gången"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1904de4..40345d1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Inaruhusu programu kuangalia vibonye unavyo bonyeza hata wakati unapo shirikiana na programu nyingine (kama vile kuweka neno). Kamwe isihitajike na programu za kawaida."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"funganisha kwa mbinu ya uingizaji"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Inaruhusu mmiliki kushurutisha kwenye kusano ya kiwango cha juu ya mbinu ya ingizo. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"funga kwa huduma ya afikiaji"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Inamuruhusu mmiliki kufunga kipengee kinachojitokeza katika nyanja mbalimbali za kiwango cha juu cha huduma ya afikiaji. Hapaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"Imefungwa kwa huduma ya maandishi"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu ya huduma ya matini(k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"funga kwa huduma ya VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Futa swali"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Wasilisha hoja"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Utafutaji wa sauti"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Mwezi 1 uliopita"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Kabla ya mwezi 1 uliopita"</string>
   <plurals name="num_seconds_ago">
@@ -1081,7 +1089,7 @@
     <string name="date_time_set" msgid="5777075614321087758">"Weka"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Imekamilika"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">" MPYA: "</font></string>
-    <string name="perms_description_app" msgid="5139836143293299417">"Zinatolewa na <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+    <string name="perms_description_app" msgid="5139836143293299417">"Imetolewa na <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"Hakuna vibali vinavyohitajika"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"Hifadhi kubwa ya USB"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB imeunganishwa"</string>
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Weka mbinu za ingizo"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Kibodi halisi"</string>
     <string name="hardware" msgid="7517821086888990278">"Maunzi"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Zindua Kivinjari?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Mara Moja tu"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw720dp-land/arrays.xml b/core/res/res/values-sw720dp-land/arrays.xml
new file mode 100644
index 0000000..d845875
--- /dev/null
+++ b/core/res/res/values-sw720dp-land/arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <array name="lockscreen_chevron_drawables">
+        <item>@drawable/ic_lockscreen_chevron_right</item>
+        <item>@null</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/core/res/res/values-sw720dp-port/arrays.xml b/core/res/res/values-sw720dp-port/arrays.xml
new file mode 100644
index 0000000..d845875
--- /dev/null
+++ b/core/res/res/values-sw720dp-port/arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <array name="lockscreen_chevron_drawables">
+        <item>@drawable/ic_lockscreen_chevron_right</item>
+        <item>@null</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 46c58e3..8de8e5e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -175,28 +175,20 @@
     <string name="permgroupdesc_location" msgid="5704679763124170100">"ตรวจดูตำแหน่งทางกายภาพของคุณ"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"การสื่อสารของเครือข่าย"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"เข้าถึงคุณลักษณะเครือข่ายต่างๆ"</string>
-    <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
-    <skip />
-    <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
-    <skip />
+    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"บลูทูธ"</string>
+    <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"เข้าถึงอุปกรณ์และเครือข่ายผ่านบลูทูธ"</string>
+    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"เครือข่ายระยะใกล้"</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"เข้าถึงอุปกรณ์ผ่านเครือข่ายระยะใกล้ เช่น NFC"</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"การตั้งค่าเสียง"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"เปลี่ยนการตั้งค่าเสียง"</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"มีผลต่อแบตเตอรี่"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"ใช้คุณลักษณะที่ทำให้พลังงานแบตเตอรี่ลดลงอย่างรวดเร็ว"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"ปฏิทิน"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"เข้าถึงปฏิทินและกิจกรรมโดยตรง"</string>
-    <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
-    <skip />
-    <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
-    <skip />
+    <string name="permgrouplab_dictionary" msgid="4148597128843641379">"อ่านพจนานุกรมผู้ใช้"</string>
+    <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"อ่านคำในพจนานุกรมผู้ใช้"</string>
+    <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"เขียนพจนานุกรมผู้ใช้"</string>
+    <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"เพิ่มคำลงในพจนานุกรมผู้ใช้"</string>
     <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"บุ๊กมาร์กและประวัติ"</string>
     <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"เข้าถึงบุ๊กมาร์กและประวัติของเบราว์เซอร์โดยตรง"</string>
     <string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"เตือน"</string>
@@ -325,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"อนุญาตให้แอปพลิเคชันดูแป้นที่คุณกดแม้ในขณะที่กำลังโต้ตอบกับแอปพลิเคชันอื่น (เช่น ขณะพิมพ์รหัสผ่าน) ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"เชื่อมโยงกับวิธีป้อนข้อมูล"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวิธีการป้อนข้อมูล ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"เชื่อมโยงกับบริการการเข้าถึง"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อระดับบนสุดของบริการการเข้าถึง ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"เชื่อมโยงกับบริการข้อความ"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการข้อความ (เช่น บริการเครื่องตรวจตัวสะกด) ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"เชื่อมโยงกับบริการ VPN"</string>
@@ -569,8 +563,7 @@
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"อนุญาตให้แอปอ่านเนื้อหาในที่จัดเก็บข้อมูล USB ซึ่งอาจรวมไปถึงรูปภาพและสื่อ"</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"อนุญาตให้แอปอ่านเนื้อหาในการ์ด SD ซึ่งอาจรวมไปถึงรูปภาพและสื่อ"</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"แก้ไขหรือลบเนื้อหาใน USB"</string>
-    <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
-    <skip />
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"แก้ไขหรือลบเนื้อหาในการ์ด SD ของคุณ"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"อนุญาตให้แอปฯ เขียนลงใน USB"</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"อนุญาตให้แอปพลิเคชันเขียนลงบนการ์ด SD"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"แก้/ลบเนื้อหาข้อมูลสื่อภายใน"</string>
@@ -862,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"ล้างข้อความค้นหา"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ส่งข้อความค้นหา"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"ค้นหาด้วยเสียง"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 เดือนที่ผ่านมา"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ก่อน 1 เดือนที่แล้ว"</string>
   <plurals name="num_seconds_ago">
@@ -1090,8 +1089,7 @@
     <string name="date_time_set" msgid="5777075614321087758">"ตั้งค่า"</string>
     <string name="date_time_done" msgid="2507683751759308828">"เสร็จสิ้น"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"ใหม่: "</font></string>
-    <!-- no translation found for perms_description_app (5139836143293299417) -->
-    <skip />
+    <string name="perms_description_app" msgid="5139836143293299417">"โดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"ที่จัดเก็บข้อมูลจำนวนมากแบบ USB"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"เชื่อมต่อ USB แล้ว"</string>
@@ -1129,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"แป้นพิมพ์บนเครื่อง"</string>
     <string name="hardware" msgid="7517821086888990278">"ฮาร์ดแวร์"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
@@ -1321,8 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"กำลังส่ง…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
-    <skip />
-    <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 70f8143..a659e9e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Pinapayagan ang app na tingnan ang mga key na iyong pinipindot kahit na nakikipag-ugnayan sa isa pang app (gaya ng pag-type ng password). Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"sumailalim sa isang pamamaraan ng pag-input"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng pamamaraan ng pag-input. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"sumailalim sa isang serbisyo sa accessibility"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Binibigyang-daan ang may-ari na sumailalim sa nasa nangungunang antas na interface ng isang serbisyo sa accessibility. Hindi dapat kailanman kailanganin para sa normal na apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"sumailalim sa serbisyo ng teksto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Pinapayagan ang may-hawak na sumailalim sa nangungunang antas na interface (hal. SpellCheckerService). Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"sumailalim sa isang serbisyo ng VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"I-clear ang query"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Isumite ang query"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Paghahanap gamit ang boses"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 buwan ang nakalipas"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Bago ang nakalipas na 1 buwan"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"I-set up paraan ng pag-input"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Aktwal na keyboard"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Ilunsad ang Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Isang Beses Lang"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9aa2df3..c9ee115 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -175,28 +175,20 @@
     <string name="permgroupdesc_location" msgid="5704679763124170100">"Fiziksel konumunuzu izleme."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Ağ iletişimi"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"Çeşitli ağ özelliklerine erişme."</string>
-    <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
-    <skip />
-    <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
-    <skip />
+    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+    <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Cihazlara ve ağlara Bluetooth ile eriş."</string>
+    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Kısa Mesafeli Ağlar"</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Cihazlara NFC gibi kısa mesafeli ağları kullanarak eriş."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Ses Ayarları"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Ses ayarlarını değiştirme."</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Pili Etkileyenler"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Pili çok çabuk tüketebilen özellikleri kullanma."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Takvim"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Takvime ve etkinliklere doğrudan erişim."</string>
-    <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
-    <skip />
-    <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
-    <skip />
+    <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Kullanıcı Sözlüğünü Oku"</string>
+    <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Kelimeleri kullanıcı sözlüğünde oku."</string>
+    <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Kullanıcı Sözlüğüne Yaz"</string>
+    <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Kelimeleri kullanıcı sözlüğüne ekle."</string>
     <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Yer İşaretleri ve Geçmiş"</string>
     <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Yer işaretlerine ve tarayıcı geçmişine doğrudan erişim."</string>
     <string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarm"</string>
@@ -325,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Uygulamaya, başka bir uygulama ile etkileşim halindeyken dahi (örneğin, şifre yazarken) bastığınız tuşları izleme izni verir. Normal uygulamalar için gerekli değildir."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"bir giriş yöntemine bağla"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cihazın sahibine, bir giriş yönteminin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"erişilebilirlik hizmetine bağlan"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"İzin sahibine bir erişilebilirlik hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"kısa mesaj hizmetine bağla"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Cihazın sahibine, bir metin hizmetinin (ör. SpellCheckerService) en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerekmez."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN hizmetine bağlan"</string>
@@ -569,8 +563,7 @@
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Uygulamaya USB depolamanın içeriğini okuma izni verir. Bu izin fotoğrafları ve medyayı da içerebilir."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Uygulamaya SD kartın içeriğini okuma izni verir. Bu izin fotoğrafları ve medyayı da içerebilir."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"USB depolamamın içeriğini değiştir veya sil"</string>
-    <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
-    <skip />
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"SD kartın içeriğini değiştir veya sil"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Uygulamaya USB depolama birimine yazma izni verir."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Uygulamaya, SD karta yazma izni verir."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"dahili medya depolama birimi içeriğini değiştir/sil"</string>
@@ -862,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Sorguyu temizle"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Sorguyu gönder"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Sesli arama"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
   <plurals name="num_seconds_ago">
@@ -1090,8 +1089,7 @@
     <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Tamamlandı"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"YENİ: "</font></string>
-    <!-- no translation found for perms_description_app (5139836143293299417) -->
-    <skip />
+    <string name="perms_description_app" msgid="5139836143293299417">"Sağlayan: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB yığın depolama"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB bağlandı"</string>
@@ -1129,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Giriş yöntemlerini ayarla"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziksel klavye"</string>
     <string name="hardware" msgid="7517821086888990278">"Donanım"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
@@ -1321,8 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"Gönderiliyor…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Tarayıcı Başlatılsın mı?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
-    <skip />
-    <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 150f728..5d06934 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Дозволяє програмі бачити клавіші, які ви натискаєте, навіть під час взаємодії з іншою програмою (як-от під час введення пароля). Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"прив\'яз. до методу введ."</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня методу введення. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прив’язуватися до служби доступності"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби доступності. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"прив’язати до текстової служби"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня текстової служби (напр. SpellCheckerService). Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"прив’язуватися до служби VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Очистити запит"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Наіслати запит"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Голосовий пошук"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 міс. тому"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раніше 1 місяця тому"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Налаштувати методи введення"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Фізична клавіатура"</string>
     <string name="hardware" msgid="7517821086888990278">"Обладнання"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запустити веб-переглядач?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Лише один раз"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 148713237..cce563a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -177,8 +177,8 @@
     <string name="permgroupdesc_network" msgid="4478299413241861987">"Truy cập các tính năng mạng khác nhau."</string>
     <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Truy cập vào các thiết bị và mạng thông qua Bluetooth."</string>
-    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Mạng tầm ngắn"</string>
-    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Truy cập vào các thiết bị thông qua mạng tầm ngắn như NFC."</string>
+    <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Mạng phạm vi ngắn"</string>
+    <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Truy cập vào các thiết bị thông qua mạng phạm vi ngắn như NFC."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Cài đặt âm thanh"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Thay đổi cài đặt âm thanh."</string>
     <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Ảnh hưởng tới pin"</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Cho phép ứng dụng xem các phím bạn nhấn ngay cả khi tương tác với ứng dụng khác (chẳng hạn như nhập mật khẩu). Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"liên kết với phương thức nhập"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của phương thức nhập. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"liên kết với dịch vụ truy cập"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ truy cập. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"liên kết với dịch vụ văn bản"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ văn bản (ví dụ: SpellCheckerService). Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"liên kết với dịch vụ VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Xóa truy vấn"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Gửi truy vấn"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Tìm kiếm bằng giọng nói"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 tháng trước"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Trước 1 tháng trước"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Thiết lập phương thức nhập"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Bàn phím thực"</string>
     <string name="hardware" msgid="7517821086888990278">"Phần cứng"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
@@ -1311,7 +1323,7 @@
     <string name="sending" msgid="3245653681008218030">"Đang gửi…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
-    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
     <skip />
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Chỉ một lần"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b2ba997..7cd2d9d 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -170,7 +170,7 @@
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"您的个人信息"</string>
     <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"直接访问您存储在名片上的信息。"</string>
     <string name="permgrouplab_socialInfo" msgid="5799096623412043791">"您的社交信息"</string>
-    <string name="permgroupdesc_socialInfo" msgid="7129842457611643493">"直接访问与您的联系人和社交关系相关的信息。"</string>
+    <string name="permgroupdesc_socialInfo" msgid="7129842457611643493">"直接访问与您的联系人和社交人脉相关的信息。"</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"您的位置"</string>
     <string name="permgroupdesc_location" msgid="5704679763124170100">"监视您的实际位置。"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"网络通信"</string>
@@ -196,9 +196,9 @@
     <string name="permgrouplab_voicemail" msgid="4162237145027592133">"语音信箱"</string>
     <string name="permgroupdesc_voicemail" msgid="2498403969862951393">"直接访问语音信箱。"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"麦克风"</string>
-    <string name="permgroupdesc_microphone" msgid="7106618286905738408">"直接访问麦克风以录制音频。"</string>
+    <string name="permgroupdesc_microphone" msgid="7106618286905738408">"直接使用麦克风以录制音频。"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"相机"</string>
-    <string name="permgroupdesc_camera" msgid="2933667372289567714">"直接访问相机以拍摄图片或视频。"</string>
+    <string name="permgroupdesc_camera" msgid="2933667372289567714">"直接使用相机以拍摄图片或视频。"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"您的应用信息"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"能够影响设备上其他应用的行为。"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"壁纸"</string>
@@ -317,10 +317,12 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"允许应用记录您所按的键,包括与其他应用进行交互(如输入密码)时按的键。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"绑定至输入法"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"允许用户绑定至输入法的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"绑定至辅助服务"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"允许应用绑定至辅助服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"绑定至文字服务"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"允许用户绑定至文字服务(如 SpellCheckerService)的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"绑定到 VPN 服务"</string>
-    <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用从不需要此权限。"</string>
+    <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到窗口小部件服务"</string>
@@ -460,9 +462,9 @@
     <string name="permlab_hardware_test" msgid="4148290860400659146">"测试硬件"</string>
     <string name="permdesc_hardware_test" msgid="6597964191208016605">"允许应用控制各种外围设备以进行硬件测试。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
-    <string name="permdesc_callPhone" msgid="6396463004110544744">"允许应用在没有您干预的情况下呼叫电话号码。恶意应用可能会产生意料之外的话费。请注意,此权限不允许应用呼叫紧急电话。"</string>
+    <string name="permdesc_callPhone" msgid="6396463004110544744">"允许应用在没有您干预的情况下拨打电话号码。恶意应用可能会产生您意料之外的话费。请注意,此权限不允许应用拨打紧急呼救电话。"</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"直接呼叫任何电话号码"</string>
-    <string name="permdesc_callPrivileged" msgid="1689024901509996810">"允许应用在没有您干预的情况下呼叫任何电话号码,包括紧急呼叫号码。恶意应用可能会向紧急服务进行多余以及非法呼叫。"</string>
+    <string name="permdesc_callPrivileged" msgid="1689024901509996810">"允许应用在没有您干预的情况下拨打任何电话号码,包括紧急呼救号码。恶意应用可能会多余以及非法地拨打紧急服务的号码。"</string>
     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"直接启动 CDMA 平板电脑设置"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"直接启动 CDMA 电话设置"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"允许应用启动 CDMA 配置。恶意应用可能会无端启动 CDMA 配置。"</string>
@@ -746,7 +748,7 @@
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"“暂停”按钮"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"“播放”按钮"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"“停止”按钮"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"只能使用紧急呼叫"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"只能使用紧急呼救"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已锁定"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 卡已用 PUK 码锁定"</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"请参阅《用户指南》或与客服人员联系。"</string>
@@ -839,7 +841,7 @@
     <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
-    <string name="save_password_never" msgid="8274330296785855105">"从不"</string>
+    <string name="save_password_never" msgid="8274330296785855105">"永不"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"您无权打开此网页。"</string>
     <string name="text_copied" msgid="4985729524670131385">"文本已复制到剪贴板。"</string>
     <string name="more_item_label" msgid="4650918923083320495">"更多"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"清除查询"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"提交查询"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"语音搜索"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月前"</string>
   <plurals name="num_seconds_ago">
@@ -1093,7 +1101,7 @@
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 已连接"</string>
     <string name="usb_storage_notification_message" msgid="939822783828183763">"触摸可将文件复制到计算机或从计算机复制到存储设备。"</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"关闭 USB 存储设备"</string>
-    <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"触摸以关闭 USB 存储设备。"</string>
+    <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"触摸可关闭 USB 存储设备。"</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB 存储设备正在使用中"</string>
     <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"在关闭 USB 存储设备前,请从计算机中卸载(“弹出”)Android 设备的 USB 存储设备。"</string>
     <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"在关闭 USB 存储设备前,请从计算机中卸载(“弹出”)Android 设备的 SD 卡。"</string>
@@ -1114,11 +1122,15 @@
     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"您卡上的所有数据都会丢失。"</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"格式化"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接 USB 调试"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"触摸以停用 USB 调试。"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"触摸可停用 USB 调试。"</string>
     <string name="select_input_method" msgid="4653387336791222978">"选择输入法"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"设置输入法"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"物理键盘"</string>
     <string name="hardware" msgid="7517821086888990278">"硬件"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
@@ -1166,7 +1178,7 @@
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"访问权限请求"</string>
     <string name="allow" msgid="7225948811296386551">"允许"</string>
     <string name="deny" msgid="2081879885755434506">"拒绝"</string>
-    <string name="permission_request_notification_title" msgid="6486759795926237907">"许可权限请求"</string>
+    <string name="permission_request_notification_title" msgid="6486759795926237907">"权限请求"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"应用对帐户 <xliff:g id="ACCOUNT">%s</xliff:g>"\n" 提出权限请求。"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"输入法"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"同步"</string>
@@ -1175,7 +1187,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
-    <string name="vpn_text" msgid="3011306607126450322">"触摸以管理网络。"</string>
+    <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"已连接到“<xliff:g id="SESSION">%s</xliff:g>”。触摸可管理网络。"</string>
     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
@@ -1184,14 +1196,14 @@
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"已启用车载模式"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"触摸可退出车载模式。"</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"网络共享或热点已启用"</string>
-    <string name="tethered_notification_message" msgid="6857031760103062982">"触摸以设置。"</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"触摸可进行设置。"</string>
     <string name="back_button_label" msgid="2300470004503343439">"上一步"</string>
     <string name="next_button_label" msgid="1080555104677992408">"下一步"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"跳过"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"手机流量过多"</string>
-    <string name="throttle_warning_notification_message" msgid="3340822228599337743">"触摸以了解有关移动数据使用的详情。"</string>
+    <string name="throttle_warning_notification_message" msgid="3340822228599337743">"触摸可了解有关移动数据使用的详情。"</string>
     <string name="throttled_notification_title" msgid="6269541897729781332">"已超出手机数据上限"</string>
-    <string name="throttled_notification_message" msgid="5443457321354907181">"触摸以了解有关移动数据使用的详情。"</string>
+    <string name="throttled_notification_message" msgid="5443457321354907181">"触摸可了解有关移动数据使用的详情。"</string>
     <string name="no_matches" msgid="8129421908915840737">"无匹配项"</string>
     <string name="find_on_page" msgid="1946799233822820384">"在网页上查找"</string>
   <plurals name="matches_found">
@@ -1281,14 +1293,14 @@
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G 数据已停用"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"移动数据已停用"</string>
     <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Wi-Fi 数据网络已停用"</string>
-    <string name="data_usage_limit_body" msgid="3317964706973601386">"触摸以启用。"</string>
+    <string name="data_usage_limit_body" msgid="3317964706973601386">"触摸可启用。"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"已超出 2G-3G 数据流量限制"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"已超出 4G 数据使用上限"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"已超出移动数据流量上限"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"超出了 Wi-Fi 数据流量上限"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"超出规定上限 <xliff:g id="SIZE">%s</xliff:g>。"</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"后台数据受限制"</string>
-    <string name="data_usage_restricted_body" msgid="6741521330997452990">"触摸以删除限制。"</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"触摸可去除限制。"</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"安全证书"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"该证书有效。"</string>
     <string name="issued_to" msgid="454239480274921032">"颁发给:"</string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"仅此一次"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 97fcbd6e..95b3fa3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"允許應用程式監看您的按鍵操作,包括使用其他應用程式時的按鍵操作,例如輸入密碼 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"連結至輸入法"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"允許應用程式繫結至輸入法的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"繫結至協助工具服務"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"允許應用程式繫結至協助工具服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"繫結至文字服務"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"允許應用程式繫結至文字服務 (例如 SpellCheckerService) 的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"繫結至 VPN 服務"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"清除查詢"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"提交查詢"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"語音搜尋"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
   <plurals name="num_seconds_ago">
@@ -1113,12 +1121,16 @@
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"USB 儲存裝置上儲存的所有檔案即將遭到清除。這項動作無法復原!"</string>
     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"儲存卡上的所有資料都會消失。"</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"格式化"</string>
-    <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 偵錯模式已啟用"</string>
+    <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
     <string name="select_input_method" msgid="4653387336791222978">"選擇輸入法"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"設定輸入法"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"實體鍵盤"</string>
     <string name="hardware" msgid="7517821086888990278">"硬體"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"啟動「瀏覽器」嗎?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"僅此一次"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dce0525..0c7d269 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -185,7 +185,7 @@
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Sebenzisa izici ezingakhipha ngokushesha ibhethri."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Ikhalenda"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Ukufinyelela okuqondile kukhalenda nezehlakalo."</string>
-    <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Funda isichzamazwi somsebenzisi"</string>
+    <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Funda isichazamazwi somsebenzisi"</string>
     <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Funda amagama kusichazamazwi somsebenzisi."</string>
     <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Bhala isichazamazwi somsebenzisi"</string>
     <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Engeza amagama kusichazamazwi somsebenzisi."</string>
@@ -317,6 +317,8 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Ivumela insiza ukuthi ibheke izinkinobho ozicindezelayo ngisho ngabe usebenzisana nezinye izinsiza (njengokubhala amaphasiwedi). Akufanele kudingakele izinsiza ezijwayelekile."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"hlanganisa indlela yokufakwayo"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa esevisini yesinqujwana"</string>
+    <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ivumela isibambi ukuhlanganisa uxhumo nomsebenzisi kwezinga eliphezulu lesevisi yesinqunjwana. Akusoze kwadingekela izinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string>
@@ -853,6 +855,12 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"xazulula umbuzo"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Thumela umbuzo"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Ukusesha ngezwi"</string>
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"inyanga engu-1 edlule"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ngaphambi kwenyanga engu-1 edlule"</string>
   <plurals name="num_seconds_ago">
@@ -1119,6 +1127,10 @@
     <string name="configure_input_methods" msgid="9091652157722495116">"Izilungiselelo zezindlela zokufakwayo"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Ukwakheka kwekhibhodi"</string>
     <string name="hardware" msgid="7517821086888990278">"I-Hardware"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
@@ -1312,5 +1324,6 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Qala Isiphequluli?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
-    <string name="activity_resolver_use_once" msgid="405646673463328329">"Kanye nje"</string>
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5fa7b7e..98e7769 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -512,7 +512,6 @@
             0 - Nothing
             1 - Recent apps dialog
             2 - Recent apps view in SystemUI
-            3 - Voice search
          This needs to match the constants in
          policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
     -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 734151b..d549644 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -227,4 +227,11 @@
          action bar tabs from becoming too wide on a wide screen when only
          a few are present. -->
     <dimen name="action_bar_stacked_tab_max_width">180dp</dimen>
+
+	<!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
+    <dimen name="notification_text_size">14dp</dimen>
+	<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
+    <dimen name="notification_title_text_size">18dp</dimen>
+	<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
+    <dimen name="notification_subtext_size">12dp</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a24e345c..a143feb 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -208,6 +208,9 @@
   <java-symbol type="id" name="inbox_text2" />
   <java-symbol type="id" name="inbox_text3" />
   <java-symbol type="id" name="inbox_text4" />
+  <java-symbol type="id" name="inbox_text5" />
+  <java-symbol type="id" name="inbox_text6" />
+  <java-symbol type="id" name="inbox_more" />
   <java-symbol type="id" name="status_bar_latest_event_content" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
@@ -294,6 +297,9 @@
   <java-symbol type="dimen" name="volume_panel_top" />
   <java-symbol type="dimen" name="action_bar_stacked_max_height" />
   <java-symbol type="dimen" name="action_bar_stacked_tab_max_width" />
+  <java-symbol type="dimen" name="notification_text_size" />
+  <java-symbol type="dimen" name="notification_title_text_size" />
+  <java-symbol type="dimen" name="notification_subtext_size" />
 
   <java-symbol type="string" name="addToDictionary" />
   <java-symbol type="string" name="action_bar_home_description" />
@@ -779,6 +785,7 @@
   <java-symbol type="string" name="serviceNotProvisioned" />
   <java-symbol type="string" name="serviceRegistered" />
   <java-symbol type="string" name="setup_autofill" />
+  <java-symbol type="string" name="share" />
   <java-symbol type="string" name="shareactionprovider_share_with" />
   <java-symbol type="string" name="shareactionprovider_share_with_application" />
   <java-symbol type="string" name="short_format_month" />
@@ -1489,6 +1496,8 @@
   <java-symbol type="string" name="low_internal_storage_view_title" />
   <java-symbol type="string" name="report" />
   <java-symbol type="string" name="select_input_method" />
+  <java-symbol type="string" name="select_keyboard_layout_notification_title" />
+  <java-symbol type="string" name="select_keyboard_layout_notification_message" />
   <java-symbol type="string" name="smv_application" />
   <java-symbol type="string" name="smv_process" />
   <java-symbol type="string" name="tethered_notification_message" />
@@ -1513,6 +1522,8 @@
   <java-symbol type="xml" name="storage_list" />
   <java-symbol type="bool" name="config_enableDreams" />
   <java-symbol type="string" name="config_defaultDreamComponent" />
+  <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
+  <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
 
   <java-symbol type="layout" name="resolver_grid" />
   <java-symbol type="id" name="resolver_grid" />
@@ -1580,6 +1591,7 @@
   <java-symbol type="drawable" name="expander_ic_minimized" />
   <java-symbol type="drawable" name="ic_menu_archive" />
   <java-symbol type="drawable" name="ic_menu_goto" />
+  <java-symbol type="drawable" name="ic_settings_language" />
   <java-symbol type="drawable" name="title_bar_medium" />
   <java-symbol type="id" name="body" />
   <java-symbol type="string" name="fast_scroll_alphabet" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 687a00b..5929439 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -846,6 +846,12 @@
         interface of an input method. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindAccessibilityService">bind to an accessibility service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindAccessibilityService">Allows the holder to bind to the top-level
+        interface of an accessibility service. Should never be needed for normal apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindTextService">bind to a text service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
@@ -2497,6 +2503,25 @@
     <!-- SearchView accessibility description for voice button [CHAR LIMIT=NONE] -->
     <string name="searchview_description_voice">Voice search</string>
 
+    <!-- Title for a warning message about the interaction model changes after allowing an accessibility
+         service to put the device into explore by touch mode, displayed as a dialog message when
+         the user selects to enables the service. (default). [CHAR LIMIT=35] -->
+    <string name="enable_explore_by_touch_warning_title">Enable Explore by Touch?</string>
+    <!-- Summary for a warning message about the interaction model changes after allowing an accessibility
+         service to put the device into explore by touch mode, displayed as a dialog message when
+         the user selects to enables the service. (tablet). [CHAR LIMIT=NONE] -->
+    <string name="enable_explore_by_touch_warning_message" product="tablet">
+            <xliff:g id="accessibility_service_name">%1$s</xliff:g> wants to enable Explore by Touch.
+            When Explore by Touch is turned on, you can hear or see descriptions of what\'s under
+            your finger or perform gestures to interact with the tablet.</string>
+    <!-- Summary for a warning message about the interaction model changes after allowing an accessibility
+         service to put the device into explore by touch mode, displayed as a dialog message when
+         the user selects to enables the service. (default). [CHAR LIMIT=NONE] -->
+    <string name="enable_explore_by_touch_warning_message" product="default">
+            <xliff:g id="accessibility_service_name">%1$s</xliff:g> wants to enable Explore by Touch.
+            When Explore by Touch is turned on, you can hear or see descriptions of what\'s under
+            your finger or perform gestures to interact with the phone.</string>
+
     <!-- String used to display the date. This is the string to say something happened 1 month ago. -->
     <string name="oneMonthDurationPast">1 month ago</string>
     <!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
@@ -3086,6 +3111,11 @@
     <!-- Title of the physical keyboard category in the input method selector [CHAR LIMIT=10] -->
     <string name="hardware">Hardware</string>
 
+    <!-- Title of the notification to prompt the user to select a keyboard layout. -->
+    <string name="select_keyboard_layout_notification_title">Select keyboard layout</string>
+    <!-- Message of the notification to prompt the user to select a keyboard layout. -->
+    <string name="select_keyboard_layout_notification_message">Touch to select a keyboard layout.</string>
+
     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
 
@@ -3566,6 +3596,6 @@
 
     <!-- Title for a button to choose the currently selected activity
          from the activity resolver to use just this once. [CHAR LIMIT=25] -->
-    <string name="activity_resolver_use_once">Just Once</string>
+    <string name="activity_resolver_use_once">Just once</string>
 
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2b34dab..a54cdf1 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -239,22 +239,25 @@
     </style>
     <!-- Notification content styles -->
     <style name="TextAppearance.StatusBar.EventContent">
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-        <item name="android:textSize">12sp</item>
+        <item name="android:textColor">#808080</item>
+        <item name="android:textSize">@dimen/notification_text_size</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Title">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textSize">@dimen/notification_title_text_size</item>
         <item name="android:textStyle">bold</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Line2">
-        <item name="android:textSize">13sp</item>
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Info">
-        <!-- inherit all -->
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
+        <item name="android:textColor">#666666</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Time">
-        <!-- inherit all -->
+        <item name="android:textSize">@dimen/notification_subtext_size</item>
+        <item name="android:textColor">#666666</item>
     </style>
 
     <style name="TextAppearance.Small.CalendarViewWeekDayView">
@@ -631,6 +634,7 @@
 
     <style name="Widget.WebView">
         <item name="android:focusable">true</item>
+        <item name="android:focusableInTouchMode">true</item>
         <item name="android:scrollbars">horizontal|vertical</item>
     </style>
 
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index cadc895..dcd1bab 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1039,7 +1039,8 @@
             </intent-filter>
         </activity>
 
-        <service android:name="android.webkit.AccessibilityInjectorTest$MockAccessibilityService">
+        <service android:name="android.webkit.AccessibilityInjectorTest$MockAccessibilityService"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
             <intent-filter>
                 <action android:name="android.accessibilityservice.AccessibilityService" />
             </intent-filter>
diff --git a/core/tests/coretests/src/android/net/SSLTest.java b/core/tests/coretests/src/android/net/SSLTest.java
index c573498..27b699d 100644
--- a/core/tests/coretests/src/android/net/SSLTest.java
+++ b/core/tests/coretests/src/android/net/SSLTest.java
@@ -59,6 +59,14 @@
                 new byte[] { 'h', 't', 't', 'p', '/', '1', '.', '1' })));
     }
 
+    public void testStringsToNpnBytesEmptyArray() {
+        try {
+            SSLCertificateSocketFactory.toNpnProtocolsList();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
     public void testStringsToNpnBytesEmptyByteArray() {
         try {
             SSLCertificateSocketFactory.toNpnProtocolsList(new byte[0]);
@@ -67,11 +75,6 @@
         }
     }
 
-    public void testStringsToNpnBytesEmptyArray() {
-        byte[] expected = {};
-        assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList()));
-    }
-
     public void testStringsToNpnBytesOversizedInput() {
         try {
             SSLCertificateSocketFactory.toNpnProtocolsList(new byte[256]);
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 544076f..782a701 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -252,6 +252,7 @@
     label:                              ' '
     base:                               ' '
     alt, meta:                          fallback SEARCH
+    ctrl:                               fallback LANGUAGE_SWITCH
 }
 
 key ENTER {
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index e592013..d90b790 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -249,6 +249,7 @@
     label:                              ' '
     base:                               ' '
     alt, meta:                          fallback SEARCH
+    ctrl:                               fallback LANGUAGE_SWITCH
 }
 
 key ENTER {
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index c41f971..dd9b554 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -180,6 +180,9 @@
 trivial getter. This is true in Froyo, but will improve in the future when
 the JIT inlines getter methods.</p>
 
+<p>Note that if you're using ProGuard, you can have the best
+of both worlds because ProGuard can inline accessors for you.</p>
+
 <a name="use_final" id="use_final"></a>
 <h2>Use Static Final For Constants</h2>
 
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 847681b..82b5e29 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -533,13 +533,19 @@
       <td>
         <code>car</code><br/>
         <code>desk</code><br/>
-        <code>television</code>
+        <code>television<br/>
+        <code>appliance</code>
       </td>
       <td>
         <ul class="nolist">
           <li>{@code car}: Device is displaying in a car dock</li>
           <li>{@code desk}: Device is displaying in a desk dock</li>
-          <li>{@code television}: Device is displaying on a television</li>
+          <li>{@code television}: Device is displaying on a television, providing
+          a "ten foot" experience where its UI is on a large screen that the
+          user is far away from, primarily oriented around DPAD or other
+          non-pointer interaction</li>
+          <li>{@code appliance}: Device is serving as an appliance, with
+          no display</li>
         </ul>
         <p><em>Added in API level 8, television added in API 13.</em></p>
         <p>This can change during the life of your application if the user places the device in a
@@ -610,15 +616,13 @@
       <td>Touchscreen type</td>
       <td>
         <code>notouch</code><br/>
-        <code>stylus</code><br/>
         <code>finger</code>
       </td>
       <td>
         <ul class="nolist">
           <li>{@code notouch}: Device does not have a touchscreen.</li>
-          <li>{@code stylus}: Device has a resistive touchscreen that's suited for use with a
-stylus.</li>
-          <li>{@code finger}: Device has a touchscreen.</li>
+          <li>{@code finger}: Device has a touchscreen that is intended to
+          be used through direction interaction of the user's finger.</li>
         </ul>
         <p>Also see the {@link android.content.res.Configuration#touchscreen} configuration field,
 which indicates the type of touchscreen on the device.</p>
@@ -694,7 +698,7 @@
 field, which indicates whether navigation keys are hidden.</p>
       </td>
     </tr>
-    <tr id="TouchQualifier">
+    <tr id="NavigationQualifier">
       <td>Primary non-touch navigation method</td>
       <td>
         <code>nonav</code><br/>
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 496e0c7..c1d3407 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -180,9 +180,9 @@
      */
     public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
         checkRecycled("decodeRegion called on recycled region decoder");
-        if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
-                || rect.bottom > getHeight())
-            throw new IllegalArgumentException("rectangle is not inside the image");
+        if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= getWidth()
+                || rect.top >= getHeight())
+            throw new IllegalArgumentException("rectangle is outside the image");
         return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
                 rect.right - rect.left, rect.bottom - rect.top, options);
     }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 5f74c01..785582c 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -386,6 +386,7 @@
 
     /**
      * Get the resolved layout direction of this Drawable.
+     * @hide
      */
     public int getResolvedLayoutDirectionSelf() {
         final Callback callback = getCallback();
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a5f653a..546925e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -296,7 +296,8 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    ALOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
+    ALOGD("%sStart display list (%p, %s, render=%d)", (char*) indent + 2, this,
+            mName.string(), isRenderable());
 
     ALOGD("%s%s %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     int saveCount = renderer.getSaveCount() - 1;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 93b065d..0ba4078 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -170,9 +170,10 @@
     }
 
     void setAlpha(float alpha) {
+        alpha = fminf(1.0f, fmaxf(0.0f, alpha));
         if (alpha != mAlpha) {
             mAlpha = alpha;
-            mMultipliedAlpha = (int)(255 * alpha);
+            mMultipliedAlpha = (int) (255 * alpha);
         }
     }
 
@@ -184,7 +185,7 @@
         if (translationX != mTranslationX) {
             mTranslationX = translationX;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
                 mMatrixFlags &= ~TRANSLATION;
             } else {
                 mMatrixFlags |= TRANSLATION;
@@ -196,7 +197,7 @@
         if (translationY != mTranslationY) {
             mTranslationY = translationY;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
                 mMatrixFlags &= ~TRANSLATION;
             } else {
                 mMatrixFlags |= TRANSLATION;
@@ -208,7 +209,7 @@
         if (rotation != mRotation) {
             mRotation = rotation;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mRotation, 0)) {
+            if (mRotation == 0.0f) {
                 mMatrixFlags &= ~ROTATION;
             } else {
                 mMatrixFlags |= ROTATION;
@@ -220,7 +221,7 @@
         if (rotationX != mRotationX) {
             mRotationX = rotationX;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+            if (mRotationX == 0.0f && mRotationY == 0.0f) {
                 mMatrixFlags &= ~ROTATION_3D;
             } else {
                 mMatrixFlags |= ROTATION_3D;
@@ -232,7 +233,7 @@
         if (rotationY != mRotationY) {
             mRotationY = rotationY;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+            if (mRotationX == 0.0f && mRotationY == 0.0f) {
                 mMatrixFlags &= ~ROTATION_3D;
             } else {
                 mMatrixFlags |= ROTATION_3D;
@@ -244,7 +245,7 @@
         if (scaleX != mScaleX) {
             mScaleX = scaleX;
             mMatrixDirty = true;
-            if (ALMOST_EQUAL(mScaleX, 1) && ALMOST_EQUAL(mScaleY, 1)) {
+            if (mScaleX == 1.0f && mScaleY == 1.0f) {
                 mMatrixFlags &= ~SCALE;
             } else {
                 mMatrixFlags |= SCALE;
@@ -267,7 +268,7 @@
     void setPivotX(float pivotX) {
         mPivotX = pivotX;
         mMatrixDirty = true;
-        if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+        if (mPivotX == 0.0f && mPivotY == 0.0f) {
             mMatrixFlags &= ~PIVOT;
         } else {
             mMatrixFlags |= PIVOT;
@@ -278,7 +279,7 @@
     void setPivotY(float pivotY) {
         mPivotY = pivotY;
         mMatrixDirty = true;
-        if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+        if (mPivotX == 0.0f && mPivotY == 0.0f) {
             mMatrixFlags &= ~PIVOT;
         } else {
             mMatrixFlags |= PIVOT;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 50f5d57..2a8b32c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -170,21 +170,32 @@
 
 void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
-    mFunctors.clear();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->fbo = getTargetFbo();
     mSaveCount = 1;
 
-    glViewport(0, 0, mWidth, mHeight);
-    mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
-
     mSnapshot->setClip(left, top, right, bottom);
-    mDirtyClip = false;
+    mDirtyClip = opaque;
+
+    syncState();
 
     if (!opaque) {
+        mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
+    } else {
+        mCaches.resetScissor();
+    }
+}
+
+void OpenGLRenderer::syncState() {
+    glViewport(0, 0, mWidth, mHeight);
+
+    if (mCaches.blend) {
+        glEnable(GL_BLEND);
+    } else {
+        glDisable(GL_BLEND);
     }
 }
 
@@ -291,11 +302,6 @@
         }
     }
 
-    // Restore state possibly changed by the functors in process mode
-    GLboolean value;
-    glGetBooleanv(GL_BLEND, &value);
-    mCaches.blend = value;
-
     mCaches.activeTexture(0);
 
     return result;
@@ -303,6 +309,8 @@
 
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     interrupt();
+    detachFunctor(functor);
+
     if (mDirtyClip) {
         setScissorFromClip();
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ab324ff..ad83b31 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -90,7 +90,7 @@
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
             int alpha, int flags);
 
-    virtual void setAlpha(float alpha) {
+    void setAlpha(float alpha) {
         mSnapshot->alpha = alpha;
     }
 
@@ -215,6 +215,12 @@
 
 private:
     /**
+     * Ensures the state of the renderer is the same as the state of
+     * the GL context.
+     */
+    void syncState();
+
+    /**
      * Saves the current state of the renderer as a new snapshot.
      * The new snapshot is saved in mSnapshot and the previous snapshot
      * is linked from mSnapshot->previous.
diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h
index f079a7b..fdd9acf 100644
--- a/libs/hwui/utils/Compare.h
+++ b/libs/hwui/utils/Compare.h
@@ -19,10 +19,6 @@
 
 #include <cmath>
 
-#define EPSILON 0.00001f
-
-#define ALMOST_EQUAL(u, v) (fabs((u) - (v)) < EPSILON)
-
 /**
  * Compare floats.
  */
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 91d8bc1..1299574 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -403,7 +403,7 @@
      * the named provider.  Periodically, the supplied LocationListener will
      * be called with the current Location or with status updates.
      *
-     * <p> It may take a while to receive the most recent location. If
+     * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
@@ -413,32 +413,61 @@
      * the {@link LocationListener#onProviderEnabled(String)} method will
      * be called and location updates will start again.
      *
-     * <p> The frequency of notification may be controlled using the
-     * minTime and minDistance parameters. If minTime is greater than 0,
-     * the LocationManager could potentially rest for minTime milliseconds
-     * between location updates to conserve power. If minDistance is greater than 0,
-     * a location will only be broadcasted if the device moves by minDistance meters.
-     * To obtain notifications as frequently as possible, set both parameters to 0.
+     * <p> The update interval can be controlled using the minTime parameter.
+     * The elapsed time between location updates will never be less than
+     * minTime, although it can be more depending on the Location Provider
+     * implementation and the update interval requested by other applications.
      *
-     * <p> Background services should be careful about setting a sufficiently high
-     * minTime so that the device doesn't consume too much power by keeping the
-     * GPS or wireless radios on all the time. In particular, values under 60000ms
-     * are not recommended.
+     * <p> Choosing a sensible value for minTime is important to conserve
+     * battery life. Each location update requires power from
+     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
+     * possible while still providing a reasonable user experience.
+     * If your application is not in the foreground and showing
+     * location to the user then your application should avoid using an active
+     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
+     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
+     * or greater. If your application is in the foreground and showing
+     * location to the user then it is appropriate to select a faster
+     * update interval.
+     *
+     * <p> The minDistance parameter can also be used to control the
+     * frequency of location updates. If it is greater than 0 then the
+     * location provider will only send your application an update when
+     * the location has changed by at least minDistance meters, AND
+     * at least minTime milliseconds have passed. However it is more
+     * difficult for location providers to save power using the minDistance
+     * parameter, so minTime should be the primary tool to conserving battery
+     * life.
+     *
+     * <p> If your application wants to passively observe location
+     * updates triggered by other applications, but not consume
+     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
+     * This provider does not actively turn on or modify active location
+     * providers, so you do not need to be as careful about minTime and
+     * minDistance. However if your application performs heavy work
+     * on a location update (such as network activity) then you should
+     * select non-zero values for minTime and/or minDistance to rate-limit
+     * your update frequency in the case another application enables a
+     * location provider with extremely fast updates.
      *
      * <p> The calling thread must be a {@link android.os.Looper} thread such as
      * the main thread of the calling Activity.
      *
+     * <p class="note"> Prior to Jellybean, the minTime parameter was
+     * only a hint, and some location provider implementations ignored it.
+     * From Jellybean and onwards it is mandatory for Android compatible
+     * devices to observe both the minTime and minDistance parameters.
+     *
      * @param provider the name of the provider with which to register
-     * @param minTime the minimum time interval for notifications, in
-     * milliseconds. This field is only used as a hint to conserve power, and actual
-     * time between location updates may be greater or lesser than this value.
-     * @param minDistance the minimum distance interval for notifications,
-     * in meters
+     * @param minTime minimum time interval between location updates, in milliseconds
+     * @param minDistance minimum distance between location updates, in meters
      * @param listener a {#link LocationListener} whose
      * {@link LocationListener#onLocationChanged} method will be called for
      * each location update
      *
-     * @throws IllegalArgumentException if provider or listener is null
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * on this device
+     * @throws IllegalArgumentException if listener is null
      * @throws RuntimeException if the calling thread has no Looper
      * @throws SecurityException if no suitable permission is present for the provider.
      */
@@ -458,7 +487,7 @@
      * the named provider.  Periodically, the supplied LocationListener will
      * be called with the current Location or with status updates.
      *
-     * <p> It may take a while to receive the most recent location. If
+     * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
@@ -468,32 +497,59 @@
      * the {@link LocationListener#onProviderEnabled(String)} method will
      * be called and location updates will start again.
      *
-     * <p> The frequency of notification may be controlled using the
-     * minTime and minDistance parameters. If minTime is greater than 0,
-     * the LocationManager could potentially rest for minTime milliseconds
-     * between location updates to conserve power. If minDistance is greater than 0,
-     * a location will only be broadcasted if the device moves by minDistance meters.
-     * To obtain notifications as frequently as possible, set both parameters to 0.
+     * <p> The update interval can be controlled using the minTime parameter.
+     * The elapsed time between location updates will never be less than
+     * minTime, although it can be more depending on the Location Provider
+     * implementation and the update interval requested by other applications.
      *
-     * <p> Background services should be careful about setting a sufficiently high
-     * minTime so that the device doesn't consume too much power by keeping the
-     * GPS or wireless radios on all the time. In particular, values under 60000ms
-     * are not recommended.
+     * <p> Choosing a sensible value for minTime is important to conserve
+     * battery life. Each location update requires power from
+     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
+     * possible while still providing a reasonable user experience.
+     * If your application is not in the foreground and showing
+     * location to the user then your application should avoid using an active
+     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
+     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
+     * or greater. If your application is in the foreground and showing
+     * location to the user then it is appropriate to select a faster
+     * update interval.
+     *
+     * <p> The minDistance parameter can also be used to control the
+     * frequency of location updates. If it is greater than 0 then the
+     * location provider will only send your application an update when
+     * the location has changed by at least minDistance meters, AND
+     * at least minTime milliseconds have passed. However it is more
+     * difficult for location providers to save power using the minDistance
+     * parameter, so minTime should be the primary tool to conserving battery
+     * life.
+     *
+     * <p> If your application wants to passively observe location
+     * updates triggered by other applications, but not consume
+     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
+     * This provider does not actively turn on or modify active location
+     * providers, so you do not need to be as careful about minTime and
+     * minDistance. However if your application performs heavy work
+     * on a location update (such as network activity) then you should
+     * select non-zero values for minTime and/or minDistance to rate-limit
+     * your update frequency in the case another application enables a
+     * location provider with extremely fast updates.
      *
      * <p> The supplied Looper is used to implement the callback mechanism.
      *
+     * <p class="note"> Prior to Jellybean, the minTime parameter was
+     * only a hint, and some location provider implementations ignored it.
+     * From Jellybean and onwards it is mandatory for Android compatible
+     * devices to observe both the minTime and minDistance parameters.
+     *
      * @param provider the name of the provider with which to register
-     * @param minTime the minimum time interval for notifications, in
-     * milliseconds. This field is only used as a hint to conserve power, and actual
-     * time between location updates may be greater or lesser than this value.
-     * @param minDistance the minimum distance interval for notifications,
-     * in meters
+     * @param minTime minimum time interval between location updates, in milliseconds
+     * @param minDistance minimum distance between location updates, in meters
      * @param listener a {#link LocationListener} whose
      * {@link LocationListener#onLocationChanged} method will be called for
      * each location update
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism.
-     * If looper is null then the callbacks will be called on the main thread.
+     * implement the callback mechanism, or null to make callbacks on the
+     * main thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
@@ -513,10 +569,10 @@
 
     /**
      * Registers the current activity to be notified periodically based on
-     * the specified criteria.  Periodically, the supplied LocationListener will
+     * the supplied criteria.  Periodically, the supplied LocationListener will
      * be called with the current Location or with status updates.
      *
-     * <p> It may take a while to receive the most recent location. If
+     * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
@@ -526,38 +582,53 @@
      * the {@link LocationListener#onProviderEnabled(String)} method will
      * be called and location updates will start again.
      *
-     * <p> The frequency of notification may be controlled using the
-     * minTime and minDistance parameters. If minTime is greater than 0,
-     * the LocationManager could potentially rest for minTime milliseconds
-     * between location updates to conserve power. If minDistance is greater than 0,
-     * a location will only be broadcasted if the device moves by minDistance meters.
-     * To obtain notifications as frequently as possible, set both parameters to 0.
+     * <p> The update interval can be controlled using the minTime parameter.
+     * The elapsed time between location updates will never be less than
+     * minTime, although it can be more depending on the Location Provider
+     * implementation and the update interval requested by other applications.
      *
-     * <p> Background services should be careful about setting a sufficiently high
-     * minTime so that the device doesn't consume too much power by keeping the
-     * GPS or wireless radios on all the time. In particular, values under 60000ms
-     * are not recommended.
+     * <p> Choosing a sensible value for minTime is important to conserve
+     * battery life. Each location update requires power from
+     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
+     * possible while still providing a reasonable user experience.
+     * If your application is not in the foreground and showing
+     * location to the user then your application should avoid using an active
+     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
+     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
+     * or greater. If your application is in the foreground and showing
+     * location to the user then it is appropriate to select a faster
+     * update interval.
+     *
+     * <p> The minDistance parameter can also be used to control the
+     * frequency of location updates. If it is greater than 0 then the
+     * location provider will only send your application an update when
+     * the location has changed by at least minDistance meters, AND
+     * at least minTime milliseconds have passed. However it is more
+     * difficult for location providers to save power using the minDistance
+     * parameter, so minTime should be the primary tool to conserving battery
+     * life.
      *
      * <p> The supplied Looper is used to implement the callback mechanism.
      *
-     * @param minTime the minimum time interval for notifications, in
-     * milliseconds. This field is only used as a hint to conserve power, and actual
-     * time between location updates may be greater or lesser than this value.
-     * @param minDistance the minimum distance interval for notifications,
-     * in meters
+     * <p class="note"> Prior to Jellybean, the minTime parameter was
+     * only a hint, and some location provider implementations ignored it.
+     * From Jellybean and onwards it is mandatory for Android compatible
+     * devices to observe both the minTime and minDistance parameters.
+     *
+     * @param minTime minimum time interval between location updates, in milliseconds
+     * @param minDistance minimum distance between location updates, in meters
      * @param criteria contains parameters for the location manager to choose the
      * appropriate provider and parameters to compute the location
      * @param listener a {#link LocationListener} whose
      * {@link LocationListener#onLocationChanged} method will be called for
      * each location update
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism.
-     * If looper is null then the callbacks will be called on the main thread.
+     * implement the callback mechanism, or null to make callbacks on the
+     * main thread.
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present to access
-     * the location services.
+     * @throws SecurityException if no suitable permission is present for the provider.
      */
     public void requestLocationUpdates(long minTime, float minDistance,
             Criteria criteria, LocationListener listener, Looper looper) {
@@ -598,43 +669,74 @@
      * the named provider.  Periodically, the supplied PendingIntent will
      * be broadcast with the current Location or with status updates.
      *
-     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     * <p> Location updates are sent with a key of
+     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
      *
-     * <p> It may take a while to receive the most recent location. If
+     * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
-     * <p> The frequency of notification or new locations may be controlled using the
-     * minTime and minDistance parameters. If minTime is greater than 0,
-     * the LocationManager could potentially rest for minTime milliseconds
-     * between location updates to conserve power. If minDistance is greater than 0,
-     * a location will only be broadcast if the device moves by minDistance meters.
-     * To obtain notifications as frequently as possible, set both parameters to 0.
+     * <p> The update interval can be controlled using the minTime parameter.
+     * The elapsed time between location updates will never be less than
+     * minTime, although it can be more depending on the Location Provider
+     * implementation and the update interval requested by other applications.
      *
-     * <p> Background services should be careful about setting a sufficiently high
-     * minTime so that the device doesn't consume too much power by keeping the
-     * GPS or wireless radios on all the time. In particular, values under 60000ms
-     * are not recommended.
+     * <p> Choosing a sensible value for minTime is important to conserve
+     * battery life. Each location update requires power from
+     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
+     * possible while still providing a reasonable user experience.
+     * If your application is not in the foreground and showing
+     * location to the user then your application should avoid using an active
+     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
+     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
+     * or greater. If your application is in the foreground and showing
+     * location to the user then it is appropriate to select a faster
+     * update interval.
      *
-     * <p> In case the provider is disabled by the user, updates will stop,
-     * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value
-     * of false.  If the provider is re-enabled, an intent will be sent with an
-     * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will
-     * start again.
+     * <p> The minDistance parameter can also be used to control the
+     * frequency of location updates. If it is greater than 0 then the
+     * location provider will only send your application an update when
+     * the location has changed by at least minDistance meters, AND
+     * at least minTime milliseconds have passed. However it is more
+     * difficult for location providers to save power using the minDistance
+     * parameter, so minTime should be the primary tool to conserving battery
+     * life.
      *
-     * <p> If the provider's status changes, an intent will be sent with an extra with key
-     * KEY_STATUS_CHANGED and an integer value indicating the new status.  Any extras associated
-     * with the status update will be sent as well.
+     * <p> If your application wants to passively observe location
+     * updates triggered by other applications, but not consume
+     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
+     * This provider does not actively turn on or modify active location
+     * providers, so you do not need to be as careful about minTime and
+     * minDistance. However if your application performs heavy work
+     * on a location update (such as network activity) then you should
+     * select non-zero values for minTime and/or minDistance to rate-limit
+     * your update frequency in the case another application enables a
+     * location provider with extremely fast updates.
+     *
+     * <p> If the provider is disabled by the user, updates will stop,
+     * and an intent will be sent with an extra with key
+     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
+     * If the provider is re-enabled, an intent will be sent with an
+     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
+     * true and location updates will start again.
+     *
+     * <p> If the provider's status changes, an intent will be sent with
+     * an extra with key {@link #KEY_STATUS_CHANGED} and an integer value
+     * indicating the new status.  Any extras associated with the status
+     * update will be sent as well.
+     *
+     * <p class="note"> Prior to Jellybean, the minTime parameter was
+     * only a hint, and some location provider implementations ignored it.
+     * From Jellybean and onwards it is mandatory for Android compatible
+     * devices to observe both the minTime and minDistance parameters.
      *
      * @param provider the name of the provider with which to register
-     * @param minTime the minimum time interval for notifications, in
-     * milliseconds. This field is only used as a hint to conserve power, and actual
-     * time between location updates may be greater or lesser than this value.
-     * @param minDistance the minimum distance interval for notifications,
-     * in meters
+     * @param minTime minimum time interval between location updates, in milliseconds
+     * @param minDistance minimum distance between location updates, in meters
      * @param intent a {#link PendingIntent} to be sent for each location update
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
+     * on this device
      * @throws IllegalArgumentException if intent is null
      * @throws SecurityException if no suitable permission is present for the provider.
      */
@@ -651,51 +753,71 @@
 
     /**
      * Registers the current activity to be notified periodically based on
-     * the specified criteria.  Periodically, the supplied PendingIntent will
+     * the supplied criteria.  Periodically, the supplied PendingIntent will
      * be broadcast with the current Location or with status updates.
      *
-     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     * <p> Location updates are sent with a key of
+     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
      *
-     * <p> It may take a while to receive the most recent location. If
+     * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
-     * <p> The frequency of notification or new locations may be controlled using the
-     * minTime and minDistance parameters. If minTime is greater than 0,
-     * the LocationManager could potentially rest for minTime milliseconds
-     * between location updates to conserve power. If minDistance is greater than 0,
-     * a location will only be broadcast if the device moves by minDistance meters.
-     * To obtain notifications as frequently as possible, set both parameters to 0.
+     * <p> The update interval can be controlled using the minTime parameter.
+     * The elapsed time between location updates will never be less than
+     * minTime, although it can be more depending on the Location Provider
+     * implementation and the update interval requested by other applications.
      *
-     * <p> Background services should be careful about setting a sufficiently high
-     * minTime so that the device doesn't consume too much power by keeping the
-     * GPS or wireless radios on all the time. In particular, values under 60000ms
-     * are not recommended.
+     * <p> Choosing a sensible value for minTime is important to conserve
+     * battery life. Each location update requires power from
+     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
+     * possible while still providing a reasonable user experience.
+     * If your application is not in the foreground and showing
+     * location to the user then your application should avoid using an active
+     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
+     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
+     * or greater. If your application is in the foreground and showing
+     * location to the user then it is appropriate to select a faster
+     * update interval.
      *
-     * <p> In case the provider is disabled by the user, updates will stop,
-     * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value
-     * of false.  If the provider is re-enabled, an intent will be sent with an
-     * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will
-     * start again.
+     * <p> The minDistance parameter can also be used to control the
+     * frequency of location updates. If it is greater than 0 then the
+     * location provider will only send your application an update when
+     * the location has changed by at least minDistance meters, AND
+     * at least minTime milliseconds have passed. However it is more
+     * difficult for location providers to save power using the minDistance
+     * parameter, so minTime should be the primary tool to conserving battery
+     * life.
      *
-     * <p> If the provider's status changes, an intent will be sent with an extra with key
-     * KEY_STATUS_CHANGED and an integer value indicating the new status.  Any extras associated
-     * with the status update will be sent as well.
+     * <p> If the provider is disabled by the user, updates will stop,
+     * and an intent will be sent with an extra with key
+     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
+     * If the provider is re-enabled, an intent will be sent with an
+     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
+     * true and location updates will start again.
      *
-     * @param minTime the minimum time interval for notifications, in
-     * milliseconds. This field is only used as a hint to conserve power, and actual
-     * time between location updates may be greater or lesser than this value.
-     * @param minDistance the minimum distance interval for notifications,
-     * in meters
+     * <p> If the provider's status changes, an intent will be sent with
+     * an extra with key {@link #KEY_STATUS_CHANGED} and an integer value
+     * indicating the new status.  Any extras associated with the status
+     * update will be sent as well.
+     *
+     * <p class="note"> Prior to Jellybean, the minTime parameter was
+     * only a hint, and some location provider implementations ignored it.
+     * From Jellybean and onwards it is mandatory for Android compatible
+     * devices to observe both the minTime and minDistance parameters.
+     *
+     * @param minTime minimum time interval between location updates, in milliseconds
+     * @param minDistance minimum distance between location updates, in meters
      * @param criteria contains parameters for the location manager to choose the
      * appropriate provider and parameters to compute the location
      * @param intent a {#link PendingIntent} to be sent for each location update
      *
-     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if intent is null
      * @throws SecurityException if no suitable permission is present for the provider.
      */
-    public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent) {
+    public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
+            PendingIntent intent) {
         if (criteria == null) {
             throw new IllegalArgumentException("criteria==null");
         }
@@ -741,12 +863,12 @@
      * {@link LocationListener#onLocationChanged} method will be called when
      * the location update is available
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism.
-     * If looper is null then the callbacks will be called on the main thread.
+     * implement the callback mechanism, or null to make callbacks on the
+     * main thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present for the provider.
+     * @throws SecurityException if no suitable permission is present for the provider
      */
     public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
         if (provider == null) {
@@ -779,13 +901,13 @@
      * {@link LocationListener#onLocationChanged} method will be called when
      * the location update is available
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism.
-     * If looper is null then the callbacks will be called on the current thread.
+     * implement the callback mechanism, or null to make callbacks on the
+     * main thread
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present to access
-     * the location services.
+     * the location services
      */
     public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
         if (criteria == null) {
@@ -804,7 +926,8 @@
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
-     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     * <p> Location updates are sent with a key of
+     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
      *
      * <p> In case the provider is disabled by the user, the update will not be received,
      * and the {@link LocationListener#onProviderDisabled(String)}
@@ -817,7 +940,7 @@
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider.
+     * @throws SecurityException if no suitable permission is present for the provider
      */
     public void requestSingleUpdate(String provider, PendingIntent intent) {
         if (provider == null) {
@@ -836,13 +959,15 @@
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
-     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     * <p> Location updates are sent with a key of
+     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
      *
-     * <p> In case the provider is disabled by the user, the update will not be received,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
+     * <p> If the provider is disabled by the user, an update will not be
+     * received, and an intent will be sent with an extra with key
+     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
+     * If the provider is re-enabled, an intent will be sent with an
+     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
+     * true and the location update will occur.
      *
      * @param criteria contains parameters for the location manager to choose the
      * appropriate provider and parameters to compute the location
@@ -850,7 +975,7 @@
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider.
+     * @throws SecurityException if no suitable permission is present for the provider
      */
     public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
         if (criteria == null) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ef5da5b..6c7c160 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1270,25 +1270,42 @@
     }
 
     /**
-     * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
-     *           headset; <var>false</var> disable A2DP audio
+     * Allow or disallow use of Bluetooth A2DP for media.
+     * <p>The default behavior of the system is to use A2DP for media playback whenever an A2DP sink
+     * is connected. Applications can use this method to override this behavior.
+     * Note that the request will not persist after a wired headset or an A2DP sink is connected or
+     * disconnected:
+     * - Connection of an A2DP sink automatically enables use of A2DP.
+     * - Connection of a wired headset automatically disables use of A2DP.
+     * - Disconnection of a wired headset automatically enables use of A2DP if an A2DP sink is
+     * connected.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+     * @param on set <var>true</var> to allow use of A2DP for media (default).
+     *               <var>false</var> to disallow use of A2DP for media.
      * @deprecated Do not use.
      */
     @Deprecated public void setBluetoothA2dpOn(boolean on){
+        IAudioService service = getService();
+        try {
+            service.setBluetoothA2dpOn(on);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setBluetoothA2dpOn", e);
+        }
     }
 
     /**
-     * Checks whether A2DP audio routing to the Bluetooth headset is on or off.
+     * Checks whether use of A2DP sinks is enabled for media.
      *
-     * @return true if A2DP audio is being routed to/from Bluetooth headset;
-     *         false if otherwise
+     * @return true if use of A2DP is enabled for media, false otherwise.
      */
     public boolean isBluetoothA2dpOn() {
-        if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
-            == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
+        IAudioService service = getService();
+        try {
+            return service.isBluetoothA2dpOn();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in isBluetoothA2dpOn", e);
             return false;
-        } else {
-            return true;
         }
     }
 
@@ -2000,6 +2017,37 @@
     }
 
     /**
+     * @hide
+     * Used internally by telephony package to register an intent receiver for ACTION_MEDIA_BUTTON.
+     * @param eventReceiver the component that will receive the media button key events,
+     *          no-op if eventReceiver is null
+     */
+    public void registerMediaButtonEventReceiverForCalls(ComponentName eventReceiver) {
+        if (eventReceiver == null) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            // eventReceiver != null
+            service.registerMediaButtonEventReceiverForCalls(eventReceiver);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in registerMediaButtonEventReceiverForCalls", e);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void unregisterMediaButtonEventReceiverForCalls() {
+        IAudioService service = getService();
+        try {
+            service.unregisterMediaButtonEventReceiverForCalls();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiverForCalls", e);
+        }
+    }
+
+    /**
      * Unregister the receiver of MEDIA_BUTTON intents.
      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 8da7d0f..5e338ab 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -59,6 +59,7 @@
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.System;
+import android.speech.RecognizerIntent;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -391,6 +392,10 @@
 
     private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
 
+    // Request to override default use of A2DP for media.
+    private boolean mBluetoothA2dpEnabled;
+    private final Object mBluetoothA2dpEnabledLock = new Object();
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -480,6 +485,7 @@
 
         mMasterVolumeRamp = context.getResources().getIntArray(
                 com.android.internal.R.array.config_masterVolumeRamp);
+
     }
 
     private void createAudioSystemThread() {
@@ -1650,6 +1656,21 @@
         return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
     }
 
+    /** @see AudioManager#setBluetoothA2dpOn() */
+    public void setBluetoothA2dpOn(boolean on) {
+        if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) {
+            return;
+        }
+        setBluetoothA2dpOnInt(on);
+    }
+
+    /** @see AudioManager#isBluetoothA2dpOn() */
+    public boolean isBluetoothA2dpOn() {
+        synchronized (mBluetoothA2dpEnabledLock) {
+            return mBluetoothA2dpEnabled;
+        }
+    }
+
     /** @see AudioManager#startBluetoothSco() */
     public void startBluetoothSco(IBinder cb){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
@@ -1672,6 +1693,7 @@
         }
     }
 
+
     private class ScoClient implements IBinder.DeathRecipient {
         private IBinder mCb; // To be notified of client's death
         private int mCreatorPid;
@@ -2893,6 +2915,11 @@
                         setOrientationForAudioSystem();
                     }
 
+                    synchronized (mBluetoothA2dpEnabledLock) {
+                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
+                                mBluetoothA2dpEnabled ?
+                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
+                    }
                     // indicate the end of reconfiguration phase to audio HAL
                     AudioSystem.setParameters("restarting=false");
                     break;
@@ -2975,6 +3002,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceAvailable(String address) {
+        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
+        // audio policy manager
+        setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
                 address);
@@ -3176,7 +3206,15 @@
                 } else {
                     device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
                 }
+                // enable A2DP before notifying headset disconnection to avoid glitches
+                if (state == 0) {
+                    setBluetoothA2dpOnInt(true);
+                }
                 handleDeviceConnection((state == 1), device, "");
+                // disable A2DP after notifying headset connection to avoid glitches
+                if (state != 0) {
+                    setBluetoothA2dpOnInt(false);
+                }
             } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) {
                 state = intent.getIntExtra("state", 0);
                 Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state);
@@ -3625,12 +3663,14 @@
             Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
             return;
         }
-        // event filtering based on audio mode
+        // event filtering for telephony
         synchronized(mRingingLock) {
-            if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
-                    (getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
-                    (getMode() == AudioSystem.MODE_RINGTONE) ) {
-                return;
+            synchronized(mRCStack) {
+                if ((mMediaReceiverForCalls != null) &&
+                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
+                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
+                    return;
+                }
             }
         }
         // event filtering based on voice-based interactions
@@ -3642,6 +3682,25 @@
     }
 
     /**
+     * Handles the dispatching of the media button events to the telephony package.
+     * Precondition: mMediaReceiverForCalls != null
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+        }
+        mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
+                mAudioHandler, Activity.RESULT_OK, null, null);
+    }
+
+    /**
      * Handles the dispatching of the media button events to one of the registered listeners,
      * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
      * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
@@ -3678,38 +3737,15 @@
     }
 
     /**
-     * The minimum duration during which a user must press to trigger voice-based interactions
-     */
-    private final static int MEDIABUTTON_LONG_PRESS_DURATION_MS = 300;
-    /**
-     * The different states of the state machine to handle the launch of voice-based interactions,
-     * stored in mVoiceButtonState.
-     */
-    private final static int VOICEBUTTON_STATE_IDLE = 0;
-    private final static int VOICEBUTTON_STATE_DOWN = 1;
-    private final static int VOICEBUTTON_STATE_DOWN_IGNORE_NEW = 2;
-    /**
-     * The different actions after state transitions on mVoiceButtonState.
+     * The different actions performed in response to a voice button key event.
      */
     private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
     private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
     private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
 
     private final Object mVoiceEventLock = new Object();
-    private int mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-    private long mVoiceButtonDownTime = 0;
-
-    /**
-     * Log an error when an unexpected action is encountered in the state machine to filter
-     * key events.
-     * @param keyAction the unexpected action of the key event being filtered
-     * @param stateName the string corresponding to the state in which the error occurred
-     */
-    private static void logErrorForKeyAction(int keyAction, String stateName) {
-        Log.e(TAG, "unexpected action "
-                + KeyEvent.actionToString(keyAction)
-                + " in " + stateName + " state");
-    }
+    private boolean mVoiceButtonDown;
+    private boolean mVoiceButtonHandled;
 
     /**
      * Filter key events that may be used for voice-based interactions
@@ -3719,67 +3755,32 @@
      *     is dispatched.
      */
     private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (DEBUG_RC) {
+            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
+        }
+
         int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
         int keyAction = keyEvent.getAction();
         synchronized (mVoiceEventLock) {
-            // state machine on mVoiceButtonState
-            switch (mVoiceButtonState) {
-
-                case VOICEBUTTON_STATE_IDLE:
-                    if (keyAction == KeyEvent.ACTION_DOWN) {
-                        mVoiceButtonDownTime = keyEvent.getDownTime();
-                        // valid state transition
-                        mVoiceButtonState = VOICEBUTTON_STATE_DOWN;
-                    } else if (keyAction == KeyEvent.ACTION_UP) {
-                        // no state transition
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else {
-                        logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_IDLE");
+            if (keyAction == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    // initial down
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled
+                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                    // long-press, start voice-based interactions
+                    mVoiceButtonHandled = true;
+                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
+                }
+            } else if (keyAction == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    // voice button up
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
                     }
-                    break;
-
-                case VOICEBUTTON_STATE_DOWN:
-                    if ((keyEvent.getEventTime() - mVoiceButtonDownTime)
-                            >= MEDIABUTTON_LONG_PRESS_DURATION_MS) {
-                        // press was long enough, start voice-based interactions, regardless of
-                        //   whether this was a DOWN or UP key event
-                        voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                        if (keyAction == KeyEvent.ACTION_UP) {
-                            // done tracking the key press, so transition back to idle state
-                            mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                            // no need to observe the upcoming key events
-                            mVoiceButtonState = VOICEBUTTON_STATE_DOWN_IGNORE_NEW;
-                        } else {
-                            logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
-                        }
-                    } else {
-                        if (keyAction == KeyEvent.ACTION_UP) {
-                            // press wasn't long enough, simulate complete key press
-                            voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                            // not tracking the key press anymore, so transition back to idle state
-                            mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                            // no state transition
-                            // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                        } else {
-                            logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
-                        }
-                    }
-                    break;
-
-                case VOICEBUTTON_STATE_DOWN_IGNORE_NEW:
-                    if (keyAction == KeyEvent.ACTION_UP) {
-                        // done tracking the key press, so transition back to idle state
-                        mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                        // no state transition: we've already launched voice-based interactions
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else  {
-                        logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN_IGNORE_NEW");
-                    }
-                    break;
+                }
             }
         }//synchronized (mVoiceEventLock)
 
@@ -3855,24 +3856,32 @@
      * Tell the system to start voice-based interactions / voice commands
      */
     private void startVoiceBasedInteractions(boolean needWakeLock) {
-        Intent voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+        Intent voiceIntent = null;
+        // select which type of search to launch:
+        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
+        //    with EXTRA_SECURE set to true if the device is securely locked
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+        if (!isLocked && pm.isScreenOn()) {
+            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+        } else {
+            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                    isLocked && mKeyguardManager.isKeyguardSecure());
+        }
+        // start the search activity
         if (needWakeLock) {
             mMediaEventWakeLock.acquire();
         }
-        voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
         try {
-            if (mKeyguardManager != null) {
-                // it's ok to start voice-based interactions when:
-                // - the device is locked but doesn't require a password to be unlocked
-                // - the device is not locked
-                if ((mKeyguardManager.isKeyguardLocked() && !mKeyguardManager.isKeyguardSecure())
-                        || !mKeyguardManager.isKeyguardLocked()) {
-                    mContext.startActivity(voiceIntent);
-                }
+            if (voiceIntent != null) {
+                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                mContext.startActivity(voiceIntent);
             }
         } catch (ActivityNotFoundException e) {
-            Log.e(TAG, "Error launching activity for ACTION_WEB_SEARCH: " + e);
+            Log.w(TAG, "No activity for search: " + e);
         } finally {
             if (needWakeLock) {
                 mMediaEventWakeLock.release();
@@ -3880,20 +3889,6 @@
         }
     }
 
-    /**
-     * Verify whether it is safe to start voice-based interactions given the state of the system
-     * @return false is the Keyguard is locked and secure, true otherwise
-     */
-    private boolean safeToStartVoiceBasedInteractions() {
-        KeyguardManager keyguard =
-                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        if (keyguard == null) {
-            return false;
-        }
-        
-        return true;
-    }
-
     private PowerManager.WakeLock mMediaEventWakeLock;
 
     private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
@@ -4028,6 +4023,12 @@
     private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
 
     /**
+     * The component the telephony package can register so telephony calls have priority to
+     * handle media button events
+     */
+    private ComponentName mMediaReceiverForCalls = null;
+
+    /**
      * Helper function:
      * Display in the log the current entries in the remote control focus stack
      */
@@ -4381,6 +4382,35 @@
     }
 
     /**
+     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
+     * precondition: c != null
+     */
+    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = c;
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
+     */
+    public void unregisterMediaButtonEventReceiverForCalls() {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = null;
+        }
+    }
+
+    /**
      * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
      * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
      *     without modifying the RC stack, but while still causing the display to refresh (will
@@ -4662,6 +4692,17 @@
     }
 
 
+    // Handles request to override default use of A2DP for media.
+    public void setBluetoothA2dpOnInt(boolean on) {
+        synchronized (mBluetoothA2dpEnabledLock) {
+            mBluetoothA2dpEnabled = on;
+            sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                    AudioSystem.FOR_MEDIA,
+                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
+                    null, 0);
+        }
+    }
+
     @Override
     public void setRingtonePlayer(IRingtonePlayer player) {
         mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 55071ec..1ca0df4 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -318,7 +318,8 @@
     public static final int FORCE_BT_DESK_DOCK = 7;
     public static final int FORCE_ANALOG_DOCK = 8;
     public static final int FORCE_DIGITAL_DOCK = 9;
-    private static final int NUM_FORCE_CONFIG = 10;
+    public static final int FORCE_NO_BT_A2DP = 10;
+    private static final int NUM_FORCE_CONFIG = 11;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
     // usage for setForceUse, must match AudioSystem::force_use
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 48f091c..7fbe28c 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -96,6 +96,10 @@
 
     boolean isBluetoothScoOn();
 
+    oneway void setBluetoothA2dpOn(boolean on);
+
+    boolean isBluetoothA2dpOn();
+
     int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
             String clientId, String callingPackageName);
 
@@ -109,6 +113,9 @@
     oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
     oneway void unregisterMediaButtonIntent(in PendingIntent pi,  in ComponentName c);
 
+    oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
+    oneway void unregisterMediaButtonEventReceiverForCalls();
+
     oneway void registerRemoteControlClient(in PendingIntent mediaIntent,
            in IRemoteControlClient rcClient, in String callingPackageName);
     oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index aa4cdbe..586f11e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -737,7 +737,7 @@
      * @see MediaPlayer#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
      */
     public void setVideoScalingMode(int mode) {
-        if (isVideoScalingModeSupported(mode)) {
+        if (!isVideoScalingModeSupported(mode)) {
             final String msg = "Scaling mode " + mode + " is not supported";
             throw new IllegalArgumentException(msg);
         }
@@ -746,6 +746,7 @@
         try {
             request.writeInterfaceToken(IMEDIA_PLAYER);
             request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
+            request.writeInt(mode);
             invoke(request, reply);
         } finally {
             request.recycle();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 821a251b..c6c1ccb 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1444,7 +1444,9 @@
         String where;
         String[] selectionArgs;
         if (mCaseInsensitivePaths) {
-            where = Files.FileColumns.DATA + " LIKE ?";
+            // the 'like' makes it use the index, the 'lower()' makes it correct
+            // when the path contains sqlite wildcard characters
+            where = "_data LIKE ?1 AND lower(_data)=lower(?1)";
             selectionArgs = new String[] { path };
         } else {
             where = Files.FileColumns.DATA + "=?";
@@ -1623,7 +1625,7 @@
                     if (line.startsWith("File")) {
                         int equals = line.indexOf('=');
                         if (equals > 0) {
-                            cachePlaylistEntry(line, playListDirectory);
+                            cachePlaylistEntry(line.substring(equals + 1), playListDirectory);
                         }
                     }
                     line = reader.readLine();
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 18aa4b3..c365e4c 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -932,8 +932,11 @@
             if (format == MtpConstants.FORMAT_ASSOCIATION) {
                 // recursive case - delete all children first
                 Uri uri = Files.getMtpObjectsUri(mVolumeName);
-                int count = mMediaProvider.delete(uri, "_data LIKE ?",
-                        new String[] { path + "/%"});
+                int count = mMediaProvider.delete(uri,
+                        // the 'like' makes it use the index, the 'lower()' makes it correct
+                        // when the path contains sqlite wildcard characters
+                        "_data LIKE ? AND lower(substr(_data,?))=lower(?)",
+                        new String[] { path + "/%", "" + path.length() + 1, path + "/"});
             }
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index da190a6..2f47aad 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,6 +16,7 @@
 
 package android.mtp;
 
+import android.content.Context;
 import android.os.storage.StorageVolume;
 
 /**
@@ -34,10 +35,10 @@
     private final boolean mRemovable;
     private final long mMaxFileSize;
 
-    public MtpStorage(StorageVolume volume) {
+    public MtpStorage(StorageVolume volume, Context context) {
         mStorageId = volume.getStorageId();
         mPath = volume.getPath();
-        mDescription = volume.getDescription();
+        mDescription = context.getResources().getString(volume.getDescriptionId());
         mReserveSpace = volume.getMtpReserveSpace();
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java b/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
index 3657d8a..8bb653b 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
@@ -111,12 +111,12 @@
     /** Frame width to be encoded, defaults to 320.
      * Actual received frame size has to match this */
     @GenerateFieldPort(name = "width", hasDefault = true)
-    private int mWidth = 320;
+    private int mWidth = 0;
 
     /** Frame height to to be encoded, defaults to 240.
      * Actual received frame size has to match */
     @GenerateFieldPort(name = "height", hasDefault = true)
-    private int mHeight = 240;
+    private int mHeight = 0;
 
     /** Stream framerate to encode the frames at.
      * By default, frames are encoded at 30 FPS*/
@@ -245,6 +245,11 @@
         if (mProfile != null) {
             mMediaRecorder.setProfile(mProfile);
             mFps = mProfile.videoFrameRate;
+            // If width and height are set larger than 0, then those
+            // overwrite the ones in the profile.
+            if (mWidth > 0 && mHeight > 0) {
+                mMediaRecorder.setVideoSize(mWidth, mHeight);
+            }
         } else {
             mMediaRecorder.setOutputFormat(mOutputFormat);
             mMediaRecorder.setVideoEncoder(mVideoEncoder);
@@ -298,7 +303,10 @@
         screenFormat.setBytesPerSample(4);
 
         int width, height;
-        if (mProfile != null) {
+        boolean widthHeightSpecified = mWidth > 0 && mHeight > 0;
+        // If width and height are specified, then use those instead
+        // of that in the profile.
+        if (mProfile != null && !widthHeightSpecified) {
             width = mProfile.videoFrameWidth;
             height = mProfile.videoFrameHeight;
         } else {
@@ -376,8 +384,6 @@
 
     @Override
     public void process(FilterContext context) {
-        if (mLogVerbose) Log.v(TAG, "Starting frame processing");
-
         GLEnvironment glEnv = context.getGLEnvironment();
         // Get input frame
         Frame input = pullInput("videoframe");
@@ -412,7 +418,6 @@
         // And swap buffers
         glEnv.swapBuffers();
         mNumFramesEncoded++;
-        if (mLogVerbose) Log.v(TAG, "numFramesEncoded = " + mNumFramesEncoded);
     }
 
     private void stopRecording(FilterContext context) {
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
index b023e42..674a2bd 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureTarget.java
@@ -121,6 +121,7 @@
     }
 
     public void updateRenderMode() {
+        if (mLogVerbose) Log.v(TAG, "updateRenderMode. Thread: " + Thread.currentThread());
         if (mRenderModeString != null) {
             if (mRenderModeString.equals("stretch")) {
                 mRenderMode = RENDERMODE_STRETCH;
@@ -139,6 +140,7 @@
 
     @Override
     public void prepare(FilterContext context) {
+        if (mLogVerbose) Log.v(TAG, "Prepare. Thread: " + Thread.currentThread());
         // Create identity shader to render, and make sure to render upside-down, as textures
         // are stored internally bottom-to-top.
         mProgram = ShaderProgram.createIdentity(context);
@@ -214,8 +216,10 @@
         float currentAspectRatio =
           (float)input.getFormat().getWidth() / input.getFormat().getHeight();
         if (currentAspectRatio != mAspectRatio) {
-            if (mLogVerbose) Log.v(TAG, "New aspect ratio: " + currentAspectRatio +
-                ", previously: " + mAspectRatio);
+            if (mLogVerbose) {
+                Log.v(TAG, "Process. New aspect ratio: " + currentAspectRatio +
+                    ", previously: " + mAspectRatio + ". Thread: " + Thread.currentThread());
+            }
             mAspectRatio = currentAspectRatio;
             updateTargetRect();
         }
@@ -249,6 +253,7 @@
 
     @Override
     public void fieldPortValueUpdated(String name, FilterContext context) {
+        if (mLogVerbose) Log.v(TAG, "FPVU. Thread: " + Thread.currentThread());
         updateRenderMode();
     }
 
@@ -260,16 +265,22 @@
     }
 
     private void updateTargetRect() {
+        if (mLogVerbose) Log.v(TAG, "updateTargetRect. Thread: " + Thread.currentThread());
         if (mScreenWidth > 0 && mScreenHeight > 0 && mProgram != null) {
             float screenAspectRatio = (float)mScreenWidth / mScreenHeight;
             float relativeAspectRatio = screenAspectRatio / mAspectRatio;
+            if (mLogVerbose) {
+                Log.v(TAG, "UTR. screen w = " + (float)mScreenWidth + " x screen h = " +
+                    (float)mScreenHeight + " Screen AR: " + screenAspectRatio +
+                    ", frame AR: "  + mAspectRatio + ", relative AR: " + relativeAspectRatio);
+            }
 
             if (relativeAspectRatio == 1.0f && mRenderMode != RENDERMODE_CUSTOMIZE) {
+                mProgram.setTargetRect(0, 0, 1, 1);
                 mProgram.setClearsOutput(false);
             } else {
                 switch (mRenderMode) {
                     case RENDERMODE_STRETCH:
-                        mProgram.setTargetRect(0, 0, 1, 1);
                         mTargetQuad.p0.set(0f, 0.0f);
                         mTargetQuad.p1.set(1f, 0.0f);
                         mTargetQuad.p2.set(0f, 1.0f);
@@ -313,6 +324,7 @@
                         ((ShaderProgram) mProgram).setSourceRegion(mSourceQuad);
                         break;
                 }
+                if (mLogVerbose) Log.v(TAG,  "UTR. quad: " + mTargetQuad);
                 ((ShaderProgram) mProgram).setTargetRegion(mTargetQuad);
             }
         }
diff --git a/packages/InputDevices/AndroidManifest.xml b/packages/InputDevices/AndroidManifest.xml
index 6831a74..f0e4abc 100644
--- a/packages/InputDevices/AndroidManifest.xml
+++ b/packages/InputDevices/AndroidManifest.xml
@@ -8,7 +8,8 @@
             android:label="@string/app_label"
             android:process="system">
 
-        <receiver android:name=".InputDeviceReceiver">
+        <receiver android:name=".InputDeviceReceiver"
+                android:label="@string/keyboard_layouts_label">
             <intent-filter>
                 <action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
             </intent-filter>
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 140c7d4..c13e606 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -3,6 +3,9 @@
     <!-- Name of the application. [CHAR LIMIT=35] -->
     <string name="app_label">Input Devices</string>
 
+    <!-- Keyboard layouts label, used to describe the set of all built-in layouts in the UI. [CHAR LIMIT=35] -->
+    <string name="keyboard_layouts_label">Android keyboard</string>
+
     <!-- US English keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_english_us_label">English (US)</string>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 50aaa9a..0165977 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,6 +34,7 @@
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.CharArrayReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.EOFException;
@@ -45,7 +46,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.zip.CRC32;
 
@@ -55,7 +60,7 @@
  */
 public class SettingsBackupAgent extends BackupAgentHelper {
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_BACKUP = DEBUG || true;
+    private static final boolean DEBUG_BACKUP = DEBUG || false;
 
     private static final String KEY_SYSTEM = "system";
     private static final String KEY_SECURE = "secure";
@@ -111,6 +116,130 @@
     private WifiManager mWfm;
     private static String mWifiConfigFile;
 
+    // Class for capturing a network definition from the wifi supplicant config file
+    static class Network {
+        String ssid = "";  // equals() and hashCode() need these to be non-null
+        String key_mgmt = "";
+        final ArrayList<String> rawLines = new ArrayList<String>();
+
+        public static Network readFromStream(BufferedReader in) {
+            final Network n = new Network();
+            String line;
+            try {
+                while (in.ready()) {
+                    line = in.readLine();
+                    if (line == null || line.startsWith("}")) {
+                        break;
+                    }
+                    n.rememberLine(line);
+                }
+            } catch (IOException e) {
+                return null;
+            }
+            return n;
+        }
+
+        void rememberLine(String line) {
+            // can't rely on particular whitespace patterns so strip leading/trailing
+            line = line.trim();
+            if (line.isEmpty()) return; // only whitespace; drop the line
+            rawLines.add(line);
+
+            // remember the ssid and key_mgmt lines for duplicate culling
+            if (line.startsWith("ssid")) {
+                ssid = line;
+            } else if (line.startsWith("key_mgmt")) {
+                key_mgmt = line;
+            }
+        }
+
+        public void write(Writer w) throws IOException {
+            w.write("\nnetwork={\n");
+            for (String line : rawLines) {
+                w.write("\t" + line + "\n");
+            }
+            w.write("}\n");
+        }
+
+        public void dump() {
+            Log.v(TAG, "network={");
+            for (String line : rawLines) {
+                Log.v(TAG, "   " + line);
+            }
+            Log.v(TAG, "}");
+        }
+
+        // Same approach as Pair.equals() and Pair.hashCode()
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) return true;
+            if (!(o instanceof Network)) return false;
+            final Network other;
+            try {
+                other = (Network) o;
+            } catch (ClassCastException e) {
+                return false;
+            }
+            return ssid.equals(other.ssid) && key_mgmt.equals(other.key_mgmt);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 17;
+            result = 31 * result + ssid.hashCode();
+            result = 31 * result + key_mgmt.hashCode();
+            return result;
+        }
+    }
+
+    // Ingest multiple wifi config file fragments, looking for network={} blocks
+    // and eliminating duplicates
+    class WifiNetworkSettings {
+        // One for fast lookup, one for maintaining ordering
+        final HashSet<Network> mKnownNetworks = new HashSet<Network>();
+        final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
+
+        public void readNetworks(BufferedReader in) {
+            try {
+                String line;
+                while (in.ready()) {
+                    line = in.readLine();
+                    if (line != null) {
+                        // Parse out 'network=' decls so we can ignore duplicates
+                        if (line.startsWith("network")) {
+                            Network net = Network.readFromStream(in);
+                            if (! mKnownNetworks.contains(net)) {
+                                if (DEBUG_BACKUP) {
+                                    Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
+                                }
+                                mKnownNetworks.add(net);
+                                mNetworks.add(net);
+                            } else {
+                                if (DEBUG_BACKUP) {
+                                    Log.v(TAG, "Dupe; skipped " + net.ssid + " / " + net.key_mgmt);
+                                }
+                            }
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                // whatever happened, we're done now
+            }
+        }
+
+        public void write(Writer w) throws IOException {
+            for (Network net : mNetworks) {
+                net.write(w);
+            }
+        }
+
+        public void dump() {
+            for (Network net : mNetworks) {
+                net.dump();
+            }
+        }
+    }
+
     @Override
     public void onCreate() {
         if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
@@ -622,29 +751,51 @@
 
     private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
         try {
-            File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
-            if (supplicantFile.exists()) supplicantFile.delete();
-            copyWifiSupplicantTemplate();
+            WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
 
-            OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
-            os.write("\n".getBytes());
-            os.write(bytes, 0, size);
-            os.close();
+            File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
+            if (supplicantFile.exists()) {
+                // Retain the existing APs; we'll append the restored ones to them
+                BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
+                supplicantImage.readNetworks(in);
+                in.close();
+
+                supplicantFile.delete();
+            }
+
+            // Incorporate the restore AP information
+            if (size > 0) {
+                char[] restoredAsBytes = new char[size];
+                for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
+                BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
+                supplicantImage.readNetworks(in);
+
+                if (DEBUG_BACKUP) {
+                    Log.v(TAG, "Final AP list:");
+                    supplicantImage.dump();
+                }
+            }
+
+            // Install the correct default template
+            BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
+            copyWifiSupplicantTemplate(bw);
+
+            // Write the restored supplicant config and we're done
+            supplicantImage.write(bw);
+            bw.close();
         } catch (IOException ioe) {
             Log.w(TAG, "Couldn't restore " + filename);
         }
     }
 
-    private void copyWifiSupplicantTemplate() {
+    private void copyWifiSupplicantTemplate(BufferedWriter bw) {
         try {
             BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
-            BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
             char[] temp = new char[1024];
             int size;
             while ((size = br.read(temp)) > 0) {
                 bw.write(temp, 0, size);
             }
-            bw.close();
             br.close();
         } catch (IOException ioe) {
             Log.w(TAG, "Couldn't copy wpa_supplicant file");
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0038d13..637c403 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -30,6 +30,7 @@
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
     <uses-permission android:name="android.permission.MASTER_CLEAR" />
+    <uses-permission android:name="android.permission.VIBRATE" />
 
     <!-- ActivityManager -->
     <uses-permission android:name="android.permission.GET_TASKS" />
@@ -54,7 +55,7 @@
         android:allowBackup="false"
         android:hardwareAccelerated="true"
         android:label="@string/app_label"
-        android:icon="@drawable/ic_launcher_settings">
+        android:icon="@*android:drawable/platlogo">
 
         <!-- Broadcast receiver that gets the broadcast at boot time and starts
              up everything else.
diff --git a/packages/SystemUI/res/anim/search_launch_enter.xml b/packages/SystemUI/res/anim/search_launch_enter.xml
new file mode 100644
index 0000000..055ea5d
--- /dev/null
+++ b/packages/SystemUI/res/anim/search_launch_enter.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false" android:zAdjustment="top">
+
+    <alpha android:fromAlpha="0" android:toAlpha="1.0"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@android:interpolator/decelerate_quad"
+            android:duration="300"/>
+
+    <translate android:fromYDelta="200" android:toYDelta="0"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@android:interpolator/decelerate_cubic"
+            android:duration="300" />
+</set>
diff --git a/packages/SystemUI/res/anim/search_launch_exit.xml b/packages/SystemUI/res/anim/search_launch_exit.xml
new file mode 100644
index 0000000..b4ed278
--- /dev/null
+++ b/packages/SystemUI/res/anim/search_launch_exit.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.
+*/
+-->
+
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+       android:interpolator="@android:anim/accelerate_interpolator"
+       android:fromXDelta="0" android:toXDelta="0"
+       android:duration="300" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png
new file mode 100644
index 0000000..11ab480
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
index daf18c7..d9ec745 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..117cf19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png
new file mode 100644
index 0000000..30e69bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
index 5292998..2cebe85 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..7c60bea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_signal_null.png
index 3733a38..709b181 100644
--- a/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..4fd3a08
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw720dp-hdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_signal_null.png
index ab718ad..67d5cbf 100644
--- a/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..1943e8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw720dp-mdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_signal_null.png
index 023bbe6..fa8735d 100644
--- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..de573b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw720dp-xhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png
new file mode 100644
index 0000000..af3e112
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
index 3e7fefd..90b8c84 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
new file mode 100644
index 0000000..5881402
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_wifi_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
index 37b6c1c..0dd081d 100644
--- a/packages/SystemUI/res/drawable/navbar_search_outerring.xml
+++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
@@ -19,5 +19,5 @@
     <size android:height="@dimen/navbar_search_outerring_diameter"
         android:width="@dimen/navbar_search_outerring_diameter" />
     <solid android:color="#00000000" />
-    <stroke android:color="#1affffff" android:width="2dp" />
+    <stroke android:color="#40ffffff" android:width="2dp" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
index 392a8b5..ae81167 100644
--- a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -55,7 +55,7 @@
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
-                prvandroid:vibrationDuration="0"
+                prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"/>
 
         </RelativeLayout>
diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
index 371c575..785d5dd 100644
--- a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
@@ -55,7 +55,7 @@
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
-                prvandroid:vibrationDuration="0"
+                prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"/>
 
         </RelativeLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
index 0ccfe95..4da05d9 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
@@ -64,7 +64,7 @@
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
-                prvandroid:vibrationDuration="0"
+                prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"/>
 
         </RelativeLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
index b9af3a9..f93dd33 100644
--- a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
@@ -26,15 +26,16 @@
     android:fitsSystemWindows="true"
     >
 
+    <include layout="@layout/status_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@*android:dimen/status_bar_height"
+        />
+
     <include layout="@layout/status_bar_expanded"
         android:layout_width="@dimen/notification_panel_width"
         android:layout_height="match_parent"
         android:layout_gravity="center_horizontal|top"
-        />
-
-    <include layout="@layout/status_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/status_bar_height"
+        android:visibility="invisible"
         />
 
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
index 0a5390a..1ae8a694 100644
--- a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
@@ -64,7 +64,7 @@
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
-                prvandroid:vibrationDuration="0"
+                prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"/>
 
         </RelativeLayout>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index b905db3..d41040d 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -69,7 +69,7 @@
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_home"
                 systemui:keyCode="3"
-                systemui:keyRepeat="true"
+                systemui:keyRepeat="false"
                 android:layout_weight="0"
                 systemui:glowBackground="@drawable/ic_sysbar_highlight"
                 android:contentDescription="@string/accessibility_home"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 4cff67b..406ed25 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,34 +23,39 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notification_panel"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
+    android:layout_height="match_parent"
     android:background="@drawable/notification_panel_bg"
     android:paddingTop="@dimen/notification_panel_padding_top"
     android:layout_marginLeft="@dimen/notification_panel_margin_left"
     >
 
-    <include layout="@layout/status_bar_expanded_header"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
- 
-    <ScrollView
-        android:id="@+id/scroll"
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:fadingEdge="none"
-        android:overScrollMode="ifContentScrolls"
-        android:layout_marginTop="@dimen/notification_panel_header_height"
         android:layout_marginBottom="@dimen/close_handle_underlap"
         >
-        <com.android.systemui.statusbar.policy.NotificationRowLayout
-            android:id="@+id/latestItems"
+
+        <include layout="@layout/status_bar_expanded_header"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            systemui:rowHeight="@dimen/notification_row_min_height"
+            android:layout_height="48dp"
             />
-    </ScrollView>
+     
+        <ScrollView
+            android:id="@+id/scroll"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:fadingEdge="none"
+            android:overScrollMode="ifContentScrolls"
+            android:layout_marginTop="@dimen/notification_panel_header_height"
+            >
+            <com.android.systemui.statusbar.policy.NotificationRowLayout
+                android:id="@+id/latestItems"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                systemui:rowHeight="@dimen/notification_row_min_height"
+                />
+        </ScrollView>
+    </FrameLayout>
 
     <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
         android:layout_width="match_parent"
@@ -67,5 +72,4 @@
             />
 
     </com.android.systemui.statusbar.phone.CloseDragHandle>
-
 </FrameLayout><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 7491939..dd70166 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -6,6 +6,7 @@
     <View
         android:id="@+id/top_glow"
         android:alpha="0"
+        android:visibility="invisible"
         android:layout_width="match_parent"
         android:layout_height="@dimen/notification_divider_height"
         android:layout_gravity="top|center_horizontal"
@@ -41,6 +42,7 @@
     <View
         android:id="@+id/bottom_glow"
         android:alpha="0"
+        android:visibility="invisible"
         android:layout_width="match_parent"
         android:layout_height="@dimen/notification_divider_height"
         android:layout_gravity="bottom|center_horizontal"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 6c31ff4..b85686f 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -26,14 +26,15 @@
     android:fitsSystemWindows="true"
     >
 
-    <include layout="@layout/status_bar_expanded"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-
     <include layout="@layout/status_bar"
         android:layout_width="match_parent"
         android:layout_height="@*android:dimen/status_bar_height"
         />
 
+    <include layout="@layout/status_bar_expanded"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"
+        />
+
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c41cf6f..2d1f644 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -47,7 +47,7 @@
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Oznámení"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
-    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavit metody vstupu"</string>
+    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavit metody zadávání"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnice"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k perifernímu zařízení USB?"</string>
@@ -77,7 +77,7 @@
     <string name="accessibility_home" msgid="8217216074895377641">"Domů"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
     <string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikace"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody vstupu"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c15a2fa..011d3a3 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -47,7 +47,7 @@
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Benachrichtigungen"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
-    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Eingabemethoden einrichten"</string>
+    <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Eingabemethoden festlegen"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physische Tastatur"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Gerät gewähren?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Zubehör gewähren?"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6b40300..f02d09ca 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -41,7 +41,7 @@
     <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
+    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -116,7 +116,7 @@
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"No SIM."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth tethering"</string>
-    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Airplane mode"</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Aeroplane mode"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Battery <xliff:g id="NUMBER">%d</xliff:g> per cent."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"System settings"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifications."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b4e0d8a..be2bf6e 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -144,10 +144,7 @@
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string>
     <string name="notifications_off_title" msgid="8936620513608443224">"Notificaciones desactivadas"</string>
     <string name="notifications_off_text" msgid="2529001315769385273">"Toca aquí para volver a activar las notificaciones."</string>
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
+    <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>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a11194e..aa4e97a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -65,7 +65,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Guardando captura..."</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Guardando captura..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"La captura de pantalla se está guardando."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla guardada"</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver la captura de pantalla"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"No se ha podido guardar la captura de pantalla. Puede que el almacenamiento esté en uso."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a242640..018b5e5 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -142,10 +142,7 @@
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programos informacija"</string>
     <string name="notifications_off_title" msgid="8936620513608443224">"Pranešimai išjungti"</string>
     <string name="notifications_off_text" msgid="2529001315769385273">"Jei norite vėl įjungti pranešimus, palieskite čia."</string>
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Užrakintas ekranas yra horizontalios orientacijos."</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Užrakintas ekranas yra vertikalios orientacijos."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 3c2e193..e708804 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -142,10 +142,7 @@
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informācija par lietotni"</string>
     <string name="notifications_off_title" msgid="8936620513608443224">"Paziņojumi ir izslēgti"</string>
     <string name="notifications_off_text" msgid="2529001315769385273">"Pieskarieties šeit, lai atkal ieslēgtu paziņojumus."</string>
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekrāns tagad ir bloķēts ainavas orientācijā."</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekrāns tagad ir bloķēts portreta orientācijā."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 77ed068..d08c529 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -142,10 +142,7 @@
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações da aplicação"</string>
     <string name="notifications_off_title" msgid="8936620513608443224">"Notificações desativadas"</string>
     <string name="notifications_off_text" msgid="2529001315769385273">"Toque aqui para voltar a ativar as notificações."</string>
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
+    <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>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5f523a2..fd41e02 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -140,10 +140,8 @@
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string>
     <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активирање чувара екрана"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информације о апликацији"</string>
-    <!-- no translation found for notifications_off_title (8936620513608443224) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (2529001315769385273) -->
-    <skip />
+    <string name="notifications_off_title" msgid="8936620513608443224">"Обавештења су искључена"</string>
+    <string name="notifications_off_text" msgid="2529001315769385273">"Додирните овде да бисте поново укључили обавештења."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран је закључан у хоризонталном положају."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран је закључан у вертикалном положају."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8ce45ed..8f22b81c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -138,8 +138,8 @@
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string>
     <string name="dreams_dock_launcher" msgid="3541196417659166245">"Amilisha hifadhi ya skrini"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Taarifa ya programu"</string>
-    <string name="notifications_off_title" msgid="8936620513608443224">"Arifa zimezimwa"</string>
-    <string name="notifications_off_text" msgid="2529001315769385273">"Gonga hapa ili kuwasha tena arifa."</string>
+    <string name="notifications_off_title" msgid="8936620513608443224">"Arifa zimelemazwa"</string>
+    <string name="notifications_off_text" msgid="2529001315769385273">"Gonga hapa ili kuwezesha tena arifa."</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrini itazunguka kiotomatiki."</string>
     <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>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 07d55f1..1bf59b0 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -28,13 +28,10 @@
     <integer name="notification_panel_layout_gravity">0x31</integer>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
-    <dimen name="navbar_search_outerring_diameter">364dp</dimen>
+    <dimen name="navbar_search_outerring_diameter">430dip</dimen>
 
     <!-- Height of search panel including navigation bar height -->
-    <dimen name="navbar_search_panel_height">300dip</dimen>
-
-    <!-- Extra space above the clock in the panel; on this device, zero -->
-    <dimen name="notification_panel_header_padding_top">0dp</dimen>
+    <dimen name="navbar_search_panel_height">280dip</dimen>
 
     <!-- Size of application thumbnail -->
     <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index dbb8d91..70f0b9b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -140,14 +140,9 @@
     <string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string>
     <string name="dreams_dock_launcher" msgid="3541196417659166245">"เปิดโปรแกรมรักษาหน้าจอ"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"ข้อมูลแอป"</string>
-    <!-- no translation found for notifications_off_title (8936620513608443224) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (2529001315769385273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="notifications_off_title" msgid="8936620513608443224">"การแจ้งเตือนปิดอยู่"</string>
+    <string name="notifications_off_text" msgid="2529001315769385273">"แตะที่นี่เพื่อเปิดการแจ้งเตือนอีกครั้ง"</string>
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวนอน"</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวตั้ง"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d0f08fc..9bf8f76 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -140,14 +140,9 @@
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
     <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ekran koruyucuyu etkinleştir"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Uygulama bilgileri"</string>
-    <!-- no translation found for notifications_off_title (8936620513608443224) -->
-    <skip />
-    <!-- no translation found for notifications_off_text (2529001315769385273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="notifications_off_title" msgid="8936620513608443224">"Bildirimler kapalı"</string>
+    <string name="notifications_off_text" msgid="2529001315769385273">"Bildirimleri tekrar açmak için buraya hafifçe vurun."</string>
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran yatay yönde kilitlendi."</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran dikey yönde kilitlendi."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 0019c7c..eef2c83 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -142,10 +142,7 @@
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Thông tin về ứng dụng"</string>
     <string name="notifications_off_title" msgid="8936620513608443224">"Tắt thông báo"</string>
     <string name="notifications_off_text" msgid="2529001315769385273">"Chạm vào đây để bật lại thông báo."</string>
-    <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
-    <skip />
-    <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
-    <skip />
+    <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Màn hình hiện bị khóa theo hướng ngang."</string>
+    <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Màn hình hiện bị khóa theo hướng dọc."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 007ee96..6433cd3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -72,7 +72,7 @@
     <string name="usb_preference_title" msgid="6551050377388882787">"USB 文件传输选项"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器 (MTP) 装载"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"作为摄像头 (PTP) 装载"</string>
-    <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于苹果机的“Android 文件传输”应用"</string>
+    <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于 Mac 的 Android 文件传输应用"</string>
     <string name="accessibility_back" msgid="567011538994429120">"返回"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"主屏幕"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"菜单"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 5548445..2786013 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -3,16 +3,16 @@
 /*
 ** Copyright 2009, 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 
+** 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 
+**     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 
+** 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.
 */
 -->
@@ -56,5 +56,8 @@
 
     <!-- Show rotation lock button in phone-style notification panel. -->
     <bool name="config_showRotationLock">true</bool>
+
+    <!-- Vibration duration for MultiWaveView used in SearchPanelView -->
+    <integer translatable="false" name="config_vibration_duration">20</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9042045..0b362d1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -59,7 +59,7 @@
     <dimen name="notification_max_height">256dp</dimen>
 
     <!-- Height of a small notification in the status bar plus glow, padding, etc -->
-    <dimen name="notification_row_min_height">72dp</dimen>
+    <dimen name="notification_row_min_height">70dp</dimen>
 
     <!-- Height of a large notification in the status bar plus glow, padding, etc -->
     <dimen name="notification_row_max_height">260dp</dimen>
@@ -74,7 +74,7 @@
     <dimen name="status_bar_icon_padding">0dp</dimen>
 
     <!-- half the distance between notifications in the panel -->
-    <dimen name="notification_divider_height">4dp</dimen>
+    <dimen name="notification_divider_height">3dp</dimen>
 
     <!-- Notification drawer tuning parameters (phone UI) -->
     <!-- Initial velocity of the shade when expanding on its own -->
@@ -115,10 +115,10 @@
     <dimen name="navbar_search_hit_radius">60dip</dimen>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
-    <dimen name="navbar_search_outerring_diameter">270dp</dimen>
+    <dimen name="navbar_search_outerring_diameter">340dp</dimen>
 
     <!-- Threshold for swipe-up gesture to activate search dialog -->
-    <dimen name="navbar_search_up_threshhold">20dip</dimen>
+    <dimen name="navbar_search_up_threshhold">40dip</dimen>
 
     <!-- Height of search panel including navigation bar height -->
     <dimen name="navbar_search_panel_height">230dip</dimen>
@@ -132,10 +132,10 @@
     <!-- Height of the notification panel header bar -->
     <dimen name="notification_panel_header_height">48dp</dimen>
 
-    <!-- Height of the notification panel header bar -->
-    <dimen name="notification_panel_padding_top">@*android:dimen/status_bar_height</dimen>
+    <!-- Extra space above the panel -->
+    <dimen name="notification_panel_padding_top">4dp</dimen>
 
-    <!-- Extra space above the clock in the panel; half of (notification_panel_header_height - 32) -->
+    <!-- Extra space above the clock in the panel -->
     <dimen name="notification_panel_header_padding_top">0dp</dimen>
 
     <!-- Layout parameters for the notification panel -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 144760e..a23fe12 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,12 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="TextAppearance.StatusBar.Title" parent="@*android:style/TextAppearance.StatusBar">
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
-        <item name="android:textStyle">bold</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
     <style name="TextAppearance.StatusBar.IntruderAlert"
         parent="@*android:style/TextAppearance.StatusBar">
     </style>
@@ -48,7 +42,7 @@
     </style>
 
     <style name="TextAppearance.StatusBar.Date" parent="@*android:style/TextAppearance.StatusBar.Icon">
-        <item name="android:textSize">16sp</item>
+        <item name="android:textSize">16dp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">@android:color/holo_blue_light</item>
     </style>
@@ -57,6 +51,7 @@
 
     <style name="TextAppearance.StatusBar.Expanded.Clock">
         <item name="android:textSize">32dp</item>
+        <item name="android:fontFamily">sans-serif-light</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#ffffff</item>
     </style>
@@ -64,7 +59,7 @@
     <style name="TextAppearance.StatusBar.Expanded.Date">
         <item name="android:textSize">12dp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#666666</item>
+        <item name="android:textColor">#cccccc</item>
         <item name="android:textAllCaps">true</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBag.java b/packages/SystemUI/src/com/android/systemui/BeanBag.java
index e4f00d6..616d72f 100644
--- a/packages/SystemUI/src/com/android/systemui/BeanBag.java
+++ b/packages/SystemUI/src/com/android/systemui/BeanBag.java
@@ -81,6 +81,10 @@
             return (float) Math.sqrt(x*x+y*y);
         }
 
+        static float clamp(float x, float a, float b) {
+            return ((x<a)?a:((x>b)?b:x));
+        }
+
         static float dot(float x1, float y1, float x2, float y2) {
             return x1*x2+y1+y2;
         }
@@ -149,6 +153,7 @@
             public boolean grabbed;
             public float grabx, graby;
             public long grabtime;
+            private float grabx_offset, graby_offset;
 
             public Bean(Context context, AttributeSet as) {
                 super(context, as);
@@ -236,17 +241,20 @@
                 switch (e.getAction()) {
                     case MotionEvent.ACTION_DOWN:
                         grabbed = true;
+                        grabx_offset = e.getRawX() - x;
+                        graby_offset = e.getRawY() - y;
                         va = 0;
                         // fall
                     case MotionEvent.ACTION_MOVE:
-                        grabx = e.getRawX();
-                        graby = e.getRawY();
+                        grabx = e.getRawX() - grabx_offset;
+                        graby = e.getRawY() - graby_offset;
                         grabtime = e.getEventTime();
                         break;
                     case MotionEvent.ACTION_CANCEL:
                     case MotionEvent.ACTION_UP:
                         grabbed = false;
-                        va = randfrange(-5,5);
+                        float a = randsign() * clamp(mag(vx, vy) * 0.33f, 0, 1080f);
+                        va = randfrange(a*0.5f, a);
                         break;
                 }
                 return true;
@@ -308,47 +316,6 @@
                             if (!(v2 instanceof Bean)) continue;
                             Bean nv2 = (Bean) v2;
                             final float overlap = nv.overlap(nv2);
-                            if (false && overlap < 0) {
-                                // angle pointing from nv2 to nv
-                                final float dx = nv.x - nv2.x;
-                                final float dy = nv.y - nv2.y;
-                                final float ang = (float) Math.atan2(dx, dy);
-
-                                if (false) {
-                                nv.vx -= Math.cos(ang) * overlap * 0.5f;
-                                nv.vy -= Math.sin(ang) * overlap * 0.5f;
-                                nv2.vx += Math.cos(ang) * overlap * 0.5f;
-                                nv2.vy += Math.sin(ang) * overlap * 0.5f;
-                                }
-
-
-                                // first, move them apart
-                                nv.x -= Math.cos(ang) * overlap/2;
-                                nv.y -= Math.sin(ang) * overlap/2;
-                                nv2.x += Math.cos(ang) * overlap/2;
-                                nv2.y += Math.sin(ang) * overlap/2;
-
-                                // next, figure out velocities
-                                final float sap = 0f; // randfrange(0,0.25f);
-
-                                final float mag1 = mag(nv.vx, nv.vy) * (1f-sap);
-                                final float mag2 = mag(nv2.vx, nv2.vy) * (1f-sap);
-
-
-                                // hacky way to transfer "momentum"
-                                nv.vx = mag2 * (float)Math.cos(ang);
-                                nv.vy = mag2 * (float)Math.sin(ang);
-                                nv2.vx = -mag1 * (float)Math.cos(ang);
-                                nv2.vy = -mag1 * (float)Math.sin(ang);
-
-                                final float totalva = nv.va + nv2.va;
-                                final float frac = randfrange(0.25f,0.75f);
-                                nv.va = totalva * frac;
-                                nv2.va = totalva * (1f-frac);
-//                                nv.va += randfrange(-20,20);
-//                                nv2.va += randfrange(-20,20);
-
-                            }
                         }
 
                         nv.setRotation(nv.a);
@@ -375,17 +342,28 @@
             boardWidth = w;
             boardHeight = h;
 //            android.util.Log.d("Nyandroid", "resized: " + w + "x" + h);
-            post(new Runnable() { public void run() {
-                reset();
-                mAnim.start();
-            } });
         }
 
+        public void startAnimation() {
+            stopAnimation();
+            if (mAnim == null) {
+                post(new Runnable() { public void run() {
+                    reset();
+                    startAnimation();
+                } });
+            } else {
+                mAnim.start();
+            }
+        }
+
+        public void stopAnimation() {
+            if (mAnim != null) mAnim.cancel();
+        }
 
         @Override
         protected void onDetachedFromWindow() {
             super.onDetachedFromWindow();
-            mAnim.cancel();
+            stopAnimation();
         }
 
         @Override
@@ -428,12 +406,19 @@
                   WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                 );
+        mBoard = new Board(this, null);
+        setContentView(mBoard);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mBoard.stopAnimation();
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        mBoard = new Board(this, null);
-        setContentView(mBoard);
+        mBoard.startAnimation();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 7a7afa7..df41d25 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -17,21 +17,21 @@
 
 package com.android.systemui;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.RectF;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
-import com.android.internal.widget.SizeAdaptiveLayout;
 
 public class ExpandHelper implements Gefingerpoken, OnClickListener {
     public interface Callback {
-        View getChildAtPosition(MotionEvent ev);
+        View getChildAtRawPosition(float x, float y);
         View getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
         boolean setUserExpandedChild(View v, boolean userxpanded);
@@ -62,6 +62,7 @@
     private Context mContext;
 
     private boolean mStretching;
+    private View mEventSource;
     private View mCurrView;
     private View mCurrViewTopGlow;
     private View mCurrViewBottomGlow;
@@ -129,8 +130,28 @@
         mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
         mScaleAnimation.setDuration(EXPAND_DURATION);
 
+        AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                View target = (View) ((ObjectAnimator) animation).getTarget();
+                if (target.getAlpha() <= 0.0f) {
+                    target.setVisibility(View.VISIBLE);
+                }
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                View target = (View) ((ObjectAnimator) animation).getTarget();
+                if (target.getAlpha() <= 0.0f) {
+                    target.setVisibility(View.INVISIBLE);
+                }
+            }
+        };
+
         mGlowTopAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
+        mGlowTopAnimation.addListener(glowVisibilityController);
         mGlowBottomAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f);
+        mGlowBottomAnimation.addListener(glowVisibilityController);
         mGlowAnimationSet = new AnimatorSet();
         mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
         mGlowAnimationSet.setDuration(GLOW_DURATION);
@@ -141,7 +162,19 @@
             @Override
             public boolean onScaleBegin(ScaleGestureDetector detector) {
                 if (DEBUG) Log.v(TAG, "onscalebegin()");
-                View v = mCallback.getChildAtPosition(detector.getFocusX(), detector.getFocusY());
+                float x = detector.getFocusX();
+                float y = detector.getFocusY();
+
+                View v = null;
+                if (mEventSource != null) {
+                    int[] location = new int[2];
+                    mEventSource.getLocationOnScreen(location);
+                    x += (float) location[0];
+                    y += (float) location[1];
+                    v = mCallback.getChildAtRawPosition(x, y);
+                } else {
+                    v = mCallback.getChildAtPosition(x, y);
+                }
 
                 // your fingers have to be somewhat close to the bounds of the view in question
                 mInitialTouchFocusY = detector.getFocusY();
@@ -189,6 +222,11 @@
             }
         });
     }
+
+    public void setEventSource(View eventSource) {
+        mEventSource = eventSource;
+    }
+
     public void setGlow(float glow) {
         if (!mGlowAnimationSet.isRunning() || glow == 0f) {
             if (mGlowAnimationSet.isRunning()) {
@@ -207,11 +245,19 @@
                     // set it explicitly in reponse to touches.
                     mCurrViewTopGlow.setAlpha(glow);
                     mCurrViewBottomGlow.setAlpha(glow);
+                    handleGlowVisibility();
                 }
             }
         }
     }
 
+    private void handleGlowVisibility() {
+        mCurrViewTopGlow.setVisibility(mCurrViewTopGlow.getAlpha() <= 0.0f ?
+                View.INVISIBLE : View.VISIBLE);
+        mCurrViewBottomGlow.setVisibility(mCurrViewBottomGlow.getAlpha() <= 0.0f ?
+                View.INVISIBLE : View.VISIBLE);
+    }
+
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
                          " stretching=" + mStretching);
@@ -223,11 +269,13 @@
         final int action = ev.getAction();
         if (DEBUG) Log.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
         if (mStretching) {
+            if (DEBUG) Log.d(TAG, "detector ontouch");
             mDetector.onTouchEvent(ev);
         }
         switch (action) {
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
+                if (DEBUG) Log.d(TAG, "cancel");
                 mStretching = false;
                 clearView();
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index c60c806..96f83c6 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -281,9 +281,16 @@
                 return;
             }
 
-            if (mBackgroundWidth < 0 || mBackgroundHeight < 0) {
-                // If we don't yet know the size of the wallpaper bitmap,
-                // we need to get it now.
+            // If we don't yet know the size of the wallpaper bitmap,
+            // we need to get it now.
+            boolean updateWallpaper = mBackgroundWidth < 0 || mBackgroundHeight < 0 ;
+
+            // If we somehow got to this point after we have last flushed
+            // the wallpaper, well we really need it to draw again.  So
+            // seems like we need to reload it.  Ouch.
+            updateWallpaper = updateWallpaper || mBackground == null;
+
+            if (updateWallpaper) {
                 updateWallpaperLocked();
             }
 
@@ -308,12 +315,6 @@
             mLastXTranslation = xPixels;
             mLastYTranslation = yPixels;
 
-            if (mBackground == null) {
-                // If we somehow got to this point after we have last flushed
-                // the wallpaper, well we really need it to draw again.  So
-                // seems like we need to reload it.  Ouch.
-                updateWallpaperLocked();
-            }
 
             if (mIsHwAccelerated) {
                 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 57f15a8..a6e4487 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -18,22 +18,27 @@
 
 import android.animation.Animator;
 import android.animation.LayoutTransition;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
 import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.speech.RecognizerIntent;
+import android.content.pm.PackageManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.widget.FrameLayout;
 
 import com.android.internal.widget.multiwaveview.MultiWaveView;
 import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
+import com.android.server.am.ActivityManagerService;
 import com.android.systemui.R;
 import com.android.systemui.recent.StatusBarTouchProxy;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -68,31 +73,58 @@
 
     private SearchManager mSearchManager;
 
+    // This code should be the same as that used in LockScreen.java
     public boolean isAssistantAvailable() {
-        return mSearchManager != null && mSearchManager.getGlobalSearchActivity() != null;
+        Intent intent = getAssistIntent();
+        return intent == null ? false
+                : mContext.getPackageManager().queryIntentActivities(intent,
+                        PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
     }
 
-    private void startAssistActivity() {
-        if (mSearchManager != null) {
-            ComponentName globalSearchActivity = mSearchManager.getGlobalSearchActivity();
+    private Intent getAssistIntent() {
+        Intent intent = null;
+        SearchManager searchManager = getSearchManager();
+        if (searchManager != null) {
+            ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
             if (globalSearchActivity != null) {
-                Intent intent = new Intent(Intent.ACTION_ASSIST);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent = new Intent(Intent.ACTION_ASSIST);
                 intent.setPackage(globalSearchActivity.getPackageName());
-                try {
-                    mContext.startActivity(intent);
-                } catch (ActivityNotFoundException e) {
-                    Slog.w(TAG, "Activity not found for " + intent.getAction());
-                }
             } else {
                 Slog.w(TAG, "No global search activity");
             }
+        } else {
+            Slog.w(TAG, "No SearchManager");
+        }
+        return intent;
+    }
+
+    private SearchManager getSearchManager() {
+        if (mSearchManager == null) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        }
+        return mSearchManager;
+    }
+
+    private void startAssistActivity() {
+        // Close Recent Apps if needed
+        mBar.animateCollapse();
+        // Launch Assist
+        Intent intent = getAssistIntent();
+        try {
+            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                    R.anim.search_launch_enter, R.anim.search_launch_exit);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent, opts.toBundle());
+        } catch (ActivityNotFoundException e) {
+            Slog.w(TAG, "Activity not found for " + intent.getAction());
         }
     }
 
     final MultiWaveView.OnTriggerListener mMultiWaveViewListener
             = new MultiWaveView.OnTriggerListener() {
 
+        private int mTarget = -1;
+
         public void onGrabbed(View v, int handle) {
         }
 
@@ -100,19 +132,26 @@
         }
 
         public void onGrabbedStateChange(View v, int handle) {
-            if (OnTriggerListener.NO_HANDLE == handle) {
+            if (mTarget == -1 && OnTriggerListener.NO_HANDLE == handle) {
                 mBar.hideSearchPanel();
             }
         }
 
         public void onTrigger(View v, int target) {
-            final int resId = mMultiWaveView.getResourceIdForTarget(target);
-            switch (resId) {
-                case com.android.internal.R.drawable.ic_lockscreen_search:
-                    startAssistActivity();
-                break;
+            mTarget = target;
+        }
+
+        public void onFinishFinalAnimation() {
+            if (mTarget != -1) {
+                final int resId = mMultiWaveView.getResourceIdForTarget(mTarget);
+                mTarget = -1; // a safety to make sure we never launch w/o prior call to onTrigger
+                switch (resId) {
+                    case com.android.internal.R.drawable.ic_lockscreen_search:
+                        startAssistActivity();
+                    break;
+                }
+                mBar.hideSearchPanel();
             }
-            mBar.hideSearchPanel();
         }
     };
 
@@ -146,6 +185,14 @@
         }
     }
 
+    private OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+        public boolean onPreDraw() {
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            mMultiWaveView.resumeAnimations();
+            return false;
+        }
+    };
+
     public void show(final boolean show, boolean animate) {
         if (animate) {
             if (mShowing != show) {
@@ -156,16 +203,20 @@
             mShowing = show;
             onAnimationEnd(null);
         }
-        postDelayed(new Runnable() {
-            public void run() {
-                setVisibility(show ? View.VISIBLE : View.INVISIBLE);
-                if (show) {
-                    setFocusable(true);
-                    setFocusableInTouchMode(true);
-                    requestFocus();
-                }
+        if (show) {
+            if (getVisibility() != View.VISIBLE) {
+                setVisibility(View.VISIBLE);
+                // Don't start the animation until we've created the layer, which is done
+                // right before we are drawn
+                mMultiWaveView.suspendAnimations();
+                getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
             }
-        }, show ? 0 : 100);
+            setFocusable(true);
+            setFocusableInTouchMode(true);
+            requestFocus();
+        } else {
+            setVisibility(View.INVISIBLE);
+        }
     }
 
     public void hide(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6584c7d..2d65dd6 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -186,6 +186,7 @@
     public void removeLongPressCallback() {
         if (mWatchLongPress != null) {
             mHandler.removeCallbacks(mWatchLongPress);
+            mWatchLongPress = null;
         }
     }
 
@@ -245,6 +246,7 @@
                 mCurrView = null;
                 mCurrAnimView = null;
                 mLongPressSent = false;
+                removeLongPressCallback();
                 break;
         }
         return mDragging;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9a76c14..8795154 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Notification;
+import android.app.Notification.BigPictureStyle;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ContentResolver;
@@ -31,9 +32,13 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.media.MediaActionSound;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -85,6 +90,7 @@
     private String mImageFileName;
     private String mImageFilePath;
     private long mImageTime;
+    private BigPictureStyle mNotificationStyle;
 
     // WORKAROUND: We want the same notification across screenshots that we update so that we don't
     // spam a user's notification drawer.  However, we only show the ticker for the saving state
@@ -109,16 +115,22 @@
         // Create the large notification icon
         int imageWidth = data.image.getWidth();
         int imageHeight = data.image.getHeight();
-        int iconWidth = data.iconSize;
-        int iconHeight = data.iconSize;
-        if (imageWidth > imageHeight) {
-            iconWidth = (int) (((float) iconHeight / imageHeight) * imageWidth);
-        } else {
-            iconHeight = (int) (((float) iconWidth / imageWidth) * imageHeight);
-        }
-        Bitmap rawIcon = Bitmap.createScaledBitmap(data.image, iconWidth, iconHeight, true);
-        Bitmap croppedIcon = Bitmap.createBitmap(rawIcon, (iconWidth - data.iconSize) / 2,
-                (iconHeight - data.iconSize) / 2, data.iconSize, data.iconSize);
+        int iconSize = data.iconSize;
+
+        final int shortSide = imageWidth < imageHeight ? imageWidth : imageHeight;
+        Bitmap preview = Bitmap.createBitmap(shortSide, shortSide, data.image.getConfig());
+        Canvas c = new Canvas(preview);
+        Paint paint = new Paint();
+        ColorMatrix desat = new ColorMatrix();
+        desat.setSaturation(0.25f);
+        paint.setColorFilter(new ColorMatrixColorFilter(desat));
+        Matrix matrix = new Matrix();
+        matrix.postTranslate((shortSide - imageWidth) / 2,
+                            (shortSide - imageHeight) / 2);
+        c.drawBitmap(data.image, matrix, paint);
+        c.drawColor(0x40FFFFFF);
+
+        Bitmap croppedIcon = Bitmap.createScaledBitmap(preview, iconSize, iconSize, true);
 
         // Show the intermediate notification
         mTickerAddSpace = !mTickerAddSpace;
@@ -131,7 +143,12 @@
             .setContentText(r.getString(R.string.screenshot_saving_text))
             .setSmallIcon(R.drawable.stat_notify_image)
             .setWhen(System.currentTimeMillis());
-        Notification n = mNotificationBuilder.getNotification();
+
+        mNotificationStyle = new Notification.BigPictureStyle()
+            .bigPicture(preview);
+        mNotificationBuilder.setStyle(mNotificationStyle);
+
+        Notification n = mNotificationBuilder.build();
         n.flags |= Notification.FLAG_NO_CLEAR;
         mNotificationManager.notify(nId, n);
 
@@ -139,6 +156,8 @@
         // on small devices, the large icon is not shown) so defer showing the large icon until
         // we compose the final post-save notification below.
         mNotificationBuilder.setLargeIcon(croppedIcon);
+        // But we still don't set it for the expanded view, allowing the smallIcon to show here.
+        mNotificationStyle.bigLargeIcon(null);
     }
 
     @Override
@@ -151,6 +170,7 @@
 
         Context context = params[0].context;
         Bitmap image = params[0].image;
+        Resources r = context.getResources();
 
         try {
             // Save the screenshot to the MediaStore
@@ -165,6 +185,14 @@
             values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
             Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
 
+            Intent sharingIntent = new Intent(Intent.ACTION_SEND);
+            sharingIntent.setType("image/png");
+            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
+            sharingIntent.setFlags(Intent.FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS);
+            mNotificationBuilder.addAction(R.drawable.ic_menu_share,
+                     r.getString(com.android.internal.R.string.share),
+                     PendingIntent.getActivity(context, 0, sharingIntent, 0));
+
             OutputStream out = resolver.openOutputStream(uri);
             image.compress(Bitmap.CompressFormat.PNG, 100, out);
             out.flush();
@@ -207,7 +235,7 @@
                 .setWhen(System.currentTimeMillis())
                 .setAutoCancel(true);
 
-            Notification n = mNotificationBuilder.getNotification();
+            Notification n = mNotificationBuilder.build();
             n.flags &= ~Notification.FLAG_NO_CLEAR;
             mNotificationManager.notify(mNotificationId, n);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ac92e1a..a352748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -539,14 +539,14 @@
         if (expandedOneU != null) {
             SizeAdaptiveLayout.LayoutParams params =
                     new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
-            params.minHeight = minHeight;
-            params.maxHeight = minHeight;
+            params.minHeight = rowHeight;
+            params.maxHeight = rowHeight;
             adaptive.addView(expandedOneU, params);
         }
         if (expandedLarge != null) {
             SizeAdaptiveLayout.LayoutParams params =
                     new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
-            params.minHeight = minHeight+1;
+            params.minHeight = rowHeight+1;
             params.maxHeight = maxHeight;
             adaptive.addView(expandedLarge, params);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 0e6dfd5..96afbb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -16,9 +16,8 @@
 
 package com.android.systemui.statusbar;
 
-import android.util.Slog;
+import android.graphics.RectF;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -29,15 +28,15 @@
     private BaseStatusBar mBar;
     private int[] mTempPoint = new int[2];
     private float[] mDownPoint = new float[2];
-    private int mOrientation;
     private float mTriggerThreshhold;
+    private boolean mPanelShowing;
+
+    RectF mInitialTouch = new RectF();
+    private boolean mStarted;
+    private boolean mSwapXY = false;
 
     public DelegateViewHelper(View sourceView) {
-        mSourceView = sourceView;
-        if (mSourceView != null) {
-            mTriggerThreshhold = mSourceView.getContext().getResources()
-                    .getDimension(R.dimen.navbar_search_up_threshhold);
-        }
+        setSourceView(sourceView);
     }
 
     public void setDelegateView(View view) {
@@ -48,47 +47,91 @@
         mBar = phoneStatusBar;
     }
 
-    public void setOrientation(int orientation) {
-        mOrientation = orientation;
-    }
-
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mBar.shouldDisableNavbarGestures()) {
+        if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
             return false;
         }
+
+        mSourceView.getLocationOnScreen(mTempPoint);
+        final float sourceX = mTempPoint[0];
+        final float sourceY = mTempPoint[1];
+
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
+                mPanelShowing = mDelegateView.getVisibility() == View.VISIBLE;
                 mDownPoint[0] = event.getX();
                 mDownPoint[1] = event.getY();
+                mStarted = mInitialTouch.contains(mDownPoint[0] + sourceX, mDownPoint[1] + sourceY);
                 break;
         }
-        if (mDelegateView != null) {
-            if (mDelegateView.getVisibility() != View.VISIBLE && event.getAction() != MotionEvent.ACTION_CANCEL) {
-                final boolean isVertical = (mOrientation == Surface.ROTATION_90
-                        || mOrientation == Surface.ROTATION_270);
-                final int historySize = event.getHistorySize();
-                for (int k = 0; k < historySize + 1; k++) {
-                    float x = k < historySize ? event.getHistoricalX(k) : event.getX();
-                    float y = k < historySize ? event.getHistoricalY(k) : event.getY();
-                    final float distance = isVertical ? (mDownPoint[0] - x) : (mDownPoint[1] - y);
-                    if (distance > mTriggerThreshhold) {
-                        mBar.showSearchPanel();
-                        break;
-                    }
+
+        if (!mStarted) {
+            return false;
+        }
+
+        if (!mPanelShowing && event.getAction() == MotionEvent.ACTION_MOVE) {
+            final int historySize = event.getHistorySize();
+            for (int k = 0; k < historySize + 1; k++) {
+                float x = k < historySize ? event.getHistoricalX(k) : event.getX();
+                float y = k < historySize ? event.getHistoricalY(k) : event.getY();
+                final float distance = mSwapXY ? (mDownPoint[0] - x) : (mDownPoint[1] - y);
+                if (distance > mTriggerThreshhold) {
+                    mBar.showSearchPanel();
+                    mPanelShowing = true;
+                    break;
                 }
             }
-            mSourceView.getLocationOnScreen(mTempPoint);
-            float deltaX = mTempPoint[0];
-            float deltaY = mTempPoint[1];
-
-            mDelegateView.getLocationOnScreen(mTempPoint);
-            deltaX -= mTempPoint[0];
-            deltaY -= mTempPoint[1];
-
-            event.offsetLocation(deltaX, deltaY);
-            mDelegateView.dispatchTouchEvent(event);
-            event.offsetLocation(-deltaX, -deltaY);
         }
-        return false;
+
+        mDelegateView.getLocationOnScreen(mTempPoint);
+        final float delegateX = mTempPoint[0];
+        final float delegateY = mTempPoint[1];
+
+        float deltaX = sourceX - delegateX;
+        float deltaY = sourceY - delegateY;
+        event.offsetLocation(deltaX, deltaY);
+        mDelegateView.dispatchTouchEvent(event);
+        event.offsetLocation(-deltaX, -deltaY);
+        return mPanelShowing;
+    }
+
+    public void setSourceView(View view) {
+        mSourceView = view;
+        if (mSourceView != null) {
+            mTriggerThreshhold = mSourceView.getContext().getResources()
+                    .getDimension(R.dimen.navbar_search_up_threshhold);
+        }
+    }
+
+    /**
+     * Selects the initial touch region based on a list of views.  This is meant to be called by
+     * a container widget on children over which the initial touch should be detected.  Note this
+     * will compute a minimum bound that contains all specified views.
+     *
+     * @param views
+     */
+    public void setInitialTouchRegion(View ... views) {
+        RectF bounds = new RectF();
+        int p[] = new int[2];
+        for (int i = 0; i < views.length; i++) {
+            View view = views[i];
+            if (view == null) continue;
+            view.getLocationOnScreen(p);
+            if (i == 0) {
+                bounds.set(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
+            } else {
+                bounds.union(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
+            }
+        }
+        mInitialTouch.set(bounds);
+    }
+
+    /**
+     * When rotation is set to NO_SENSOR, then this allows swapping x/y for gesture detection
+     * @param swap
+     */
+    public void setSwapXY(boolean swap) {
+        mSwapXY = swap;
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 2f02d23..1321ade 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -21,9 +21,9 @@
 import android.util.Slog;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import com.android.systemui.statusbar.policy.NetworkController;
 
@@ -31,12 +31,12 @@
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView
-        extends LinearLayout 
+        extends LinearLayout
         implements NetworkController.SignalCluster {
 
     static final boolean DEBUG = false;
     static final String TAG = "SignalClusterView";
-    
+
     NetworkController mNC;
 
     private boolean mWifiVisible = false;
@@ -132,6 +132,17 @@
         apply();
     }
 
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        // Standard group layout onPopulateAccessibilityEvent() implementations
+        // ignore content description, so populate manually
+        if (mWifiVisible && mWifiGroup.getContentDescription() != null)
+            event.getText().add(mWifiGroup.getContentDescription());
+        if (mMobileVisible && mMobileGroup.getContentDescription() != null)
+            event.getText().add(mMobileGroup.getContentDescription());
+        return super.dispatchPopulateAccessibilityEvent(event);
+    }
+
     // Run after each indicator change.
     private void apply() {
         if (mWifiGroup == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4bb2d1d..9c773a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
@@ -113,6 +114,14 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mDelegateHelper != null) {
+            mDelegateHelper.onInterceptTouchEvent(event);
+        }
+        return true;
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
         return mDelegateHelper.onInterceptTouchEvent(event);
     }
@@ -292,6 +301,7 @@
         setLowProfile(false);
     }
 
+    @Override
     public void onFinishInflate() {
         mRotatedViews[Surface.ROTATION_0] = 
         mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
@@ -330,6 +340,12 @@
     }
 
     @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton());
+    }
+
+    @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         if (DEBUG) Slog.d(TAG, String.format(
                     "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2ea1827..b9dd32f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -33,8 +33,12 @@
 import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.os.Message;
@@ -45,7 +49,6 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
-import android.util.TypedValue;
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.Gravity;
@@ -56,20 +59,16 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.widget.CompoundButton;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.RemoteViews;
 import android.widget.ScrollView;
 import android.widget.TextView;
-
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
@@ -80,7 +79,6 @@
 import com.android.systemui.statusbar.RotationToggle;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.policy.AutoRotateController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.IntruderAlertView;
@@ -224,6 +222,18 @@
     DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
     private int mNavigationIconHints = 0;
+    private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mIcons.setVisibility(View.INVISIBLE);
+        }
+    };
+    private final Animator.AnimatorListener mMakeIconsVisible = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mIcons.setVisibility(View.VISIBLE);
+        }
+    };
 
     private class ExpandedDialog extends Dialog {
         ExpandedDialog(Context context) {
@@ -289,7 +299,7 @@
                         animateCollapse();
                     }
                 }
-                return true;
+                return mStatusBarWindow.onTouchEvent(event);
             }});
 
         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
@@ -301,11 +311,14 @@
                 return true;
             }
         });
+        mNotificationPanel.setSystemUiVisibility(
+                  View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
+                | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
 
         if (!ActivityManager.isHighEndGfx(mDisplay)) {
             mStatusBarWindow.setBackground(null);
-            mNotificationPanel.setBackgroundColor(context.getResources().getColor(
-                    R.color.notification_panel_solid_background));
+            mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
+                    R.color.notification_panel_solid_background)));
         }
 
         if (ENABLE_INTRUDERS) {
@@ -336,7 +349,6 @@
         mPixelFormat = PixelFormat.OPAQUE;
         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
-        mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
         mIcons = (LinearLayout)mStatusBarView.findViewById(R.id.icons);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
@@ -348,6 +360,7 @@
         mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
         mClearButton.setOnClickListener(mClearButtonListener);
         mClearButton.setAlpha(0f);
+        mClearButton.setVisibility(View.INVISIBLE);
         mClearButton.setEnabled(false);
         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
         mSettingsButton = mStatusBarWindow.findViewById(R.id.settings_button);
@@ -513,14 +526,8 @@
         public boolean onTouch(View v, MotionEvent event) {
             switch(event.getAction()) {
                 case MotionEvent.ACTION_DOWN:
-                    Slog.d(TAG, "showing search panel");
                     showSearchPanel();
                 break;
-
-                case MotionEvent.ACTION_UP:
-                    Slog.d(TAG, "hiding search panel");
-                    hideSearchPanel();
-                break;
             }
             return false;
         }
@@ -531,8 +538,8 @@
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
         updateSearchPanel();
-//        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
     }
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
@@ -810,16 +817,31 @@
 
         if (mClearButton.isShown()) {
             if (clearable != (mClearButton.getAlpha() == 1.0f)) {
-                ObjectAnimator.ofFloat(mClearButton, "alpha",
-                        clearable ? 1.0f : 0.0f)
-                    .setDuration(250)
-                    .start();
+                ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
+                        mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
+                clearAnimation.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (mClearButton.getAlpha() <= 0.0f) {
+                            mClearButton.setVisibility(View.INVISIBLE);
+                        }
+                    }
+
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        if (mClearButton.getAlpha() <= 0.0f) {
+                            mClearButton.setVisibility(View.VISIBLE);
+                        }
+                    }
+                });
+                clearAnimation.start();
             }
         } else {
             mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
+            mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
         }
         mClearButton.setEnabled(clearable);
-        
+
         final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
         final boolean showDot = (any&&!areLightsOn());
         if (showDot != (nlo.getAlpha() == 1.0f)) {
@@ -884,6 +906,17 @@
         flagdbg.append(((diff  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
         flagdbg.append(">");
         Slog.d(TAG, flagdbg.toString());
+        
+        if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+            mIcons.animate().cancel();
+            if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+                mIcons.animate().alpha(0f).setStartDelay(100).setDuration(200).
+                        setListener(mMakeIconsInvisible).start();
+            } else {
+                mIcons.animate().alpha(1f).setStartDelay(0).setDuration(300).
+                        setListener(mMakeIconsVisible).start();
+            }
+        }
 
         if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
             boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
@@ -985,6 +1018,7 @@
         }
         
         mExpandedVisible = true;
+        mNotificationPanel.setVisibility(View.VISIBLE);
 
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
@@ -1035,6 +1069,8 @@
             mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
             mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
         }
+        mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+        mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
 
         if (!mExpandedVisible) {
             return;
@@ -1078,7 +1114,7 @@
         }
         mExpandedVisible = false;
         visibilityChanged(false);
-        //mNotificationPanel.setVisibility(View.GONE);
+        mNotificationPanel.setVisibility(View.INVISIBLE);
 
         // Shrink the window to the size of the status bar only
         WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
@@ -1786,7 +1822,6 @@
         }
 
         int panelh = 0;
-        final boolean portrait = mDisplayMetrics.heightPixels > mDisplayMetrics.widthPixels;
         
         final int disph = getExpandedViewMaxHeight();
 
@@ -2114,5 +2149,38 @@
     protected boolean shouldDisableNavbarGestures() {
         return mExpanded || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
     }
-}
 
+    private static class FastColorDrawable extends Drawable {
+        private final int mColor;
+
+        public FastColorDrawable(int color) {
+            mColor = 0xff000000 | color;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.drawColor(mColor, PorterDuff.Mode.SRC);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+
+        @Override
+        public void setBounds(int left, int top, int right, int bottom) {
+        }
+
+        @Override
+        public void setBounds(Rect bounds) {
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 0fc5b4d..ed1b2f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -18,17 +18,39 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.widget.FrameLayout;
 import android.widget.TextSwitcher;
 
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NotificationRowLayout;
+
 
 public class StatusBarWindowView extends FrameLayout
 {
+    private static final String TAG = "StatusBarWindowView";
+
+    private ExpandHelper mExpandHelper;
+    private NotificationRowLayout latestItems;
+
     PhoneStatusBar mService;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setMotionEventSplittingEnabled(false);
+    }
+
+    @Override
+    protected void onAttachedToWindow () {
+        super.onAttachedToWindow();
+        latestItems = (NotificationRowLayout) findViewById(R.id.latestItems);
+        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+        mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
+        mExpandHelper.setEventSource(this);
     }
 
     @Override
@@ -43,5 +65,25 @@
         }
         return super.dispatchKeyEvent(event);
     }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        MotionEvent cancellation = MotionEvent.obtain(ev);
+        cancellation.setAction(MotionEvent.ACTION_CANCEL);
+
+        boolean intercept = mExpandHelper.onInterceptTouchEvent(ev) ||
+                super.onInterceptTouchEvent(ev);
+        if (intercept) {
+            latestItems.onInterceptTouchEvent(cancellation);
+        }
+        return intercept;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = mExpandHelper.onTouchEvent(ev) ||
+                super.onTouchEvent(ev);
+        return handled;
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
index a31e2a4..3d63781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
@@ -18,32 +18,40 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.util.Log;
-import android.util.Slog;
 import android.view.IWindowManager;
 import android.widget.CompoundButton;
 
-/**
- * TODO: Listen for changes to the setting.
- */
 public class AutoRotateController implements CompoundButton.OnCheckedChangeListener {
     private static final String TAG = "StatusBar.AutoRotateController";
 
-    private Context mContext;
-    private CompoundButton mCheckBox;
+    private final Context mContext;
+    private final CompoundButton mCheckbox;
 
     private boolean mAutoRotation;
 
+    private ContentObserver mAccelerometerRotationObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateCheckbox();
+        }
+    };
+
     public AutoRotateController(Context context, CompoundButton checkbox) {
         mContext = context;
-        mAutoRotation = getAutoRotation();
-        mCheckBox = checkbox;
-        checkbox.setChecked(mAutoRotation);
-        checkbox.setOnCheckedChangeListener(this);
+        mCheckbox = checkbox;
+        updateCheckbox();
+        mCheckbox.setOnCheckedChangeListener(this);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), true,
+                mAccelerometerRotationObserver);
     }
 
     public void onCheckedChanged(CompoundButton view, boolean checked) {
@@ -52,6 +60,15 @@
         }
     }
 
+    public void release() {
+        mContext.getContentResolver().unregisterContentObserver(mAccelerometerRotationObserver);
+    }
+
+    private void updateCheckbox() {
+        mAutoRotation = getAutoRotation();
+        mCheckbox.setChecked(mAutoRotation);
+    }
+
     private boolean getAutoRotation() {
         ContentResolver cr = mContext.getContentResolver();
         return 0 != Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index a00fab3..bb0ce16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,6 +52,7 @@
     int mCode;
     int mTouchSlop;
     Drawable mGlowBG;
+    int mGlowWidth, mGlowHeight;
     float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
     boolean mSupportsLongpress = true;
     RectF mRect = new RectF(0f,0f,0f,0f);
@@ -89,6 +90,8 @@
         mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
         if (mGlowBG != null) {
             setDrawingAlpha(BUTTON_QUIESCENT_ALPHA);
+            mGlowWidth = mGlowBG.getIntrinsicWidth();
+            mGlowHeight = mGlowBG.getIntrinsicHeight();
         }
         
         a.recycle();
@@ -103,8 +106,12 @@
             canvas.save();
             final int w = getWidth();
             final int h = getHeight();
+            final float aspect = (float)mGlowWidth / mGlowHeight;
+            final int drawW = (int)(h*aspect);
+            final int drawH = h;
+            final int margin = (drawW-w)/2;
             canvas.scale(mGlowScale, mGlowScale, w*0.5f, h*0.5f);
-            mGlowBG.setBounds(0, 0, w, h);
+            mGlowBG.setBounds(-margin, 0, drawW-margin, drawH);
             mGlowBG.setAlpha((int)(mDrawingAlpha * mGlowAlpha * 255));
             mGlowBG.draw(canvas);
             canvas.restore();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index a05fcc1..c65f581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -282,7 +282,8 @@
 
     public void refreshSignalCluster(SignalCluster cluster) {
         cluster.setWifiIndicators(
-                mWifiConnected, // only show wifi in the cluster if connected
+                // only show wifi in the cluster if connected or if wifi-only
+                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
                 mWifiIconId,
                 mWifiActivityIconId,
                 mContentDescriptionWifi);
@@ -786,7 +787,7 @@
             if (mDataAndWifiStacked) {
                 mWifiIconId = 0;
             } else {
-                mWifiIconId = mWifiEnabled ? WifiIcons.WIFI_SIGNAL_STRENGTH[0][0] : 0;
+                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
             }
             mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index f41d99c..0284644 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -36,7 +36,6 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.ExpandHelper;
-import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.NotificationData;
@@ -62,9 +61,6 @@
     HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
 
     private SwipeHelper mSwipeHelper;
-    private ExpandHelper mExpandHelper;
-
-    private Gefingerpoken mCurrentHelper;
 
     // Flag set during notification removal animation to avoid causing too much work until
     // animation is done
@@ -81,8 +77,6 @@
         
         setOrientation(LinearLayout.VERTICAL);
 
-        setMotionEventSplittingEnabled(false);
-
         if (DEBUG) {
             setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                 @Override
@@ -101,9 +95,6 @@
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
-        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
-        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
-        mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
     }
 
     public void setLongPressListener(View.OnLongClickListener listener) {
@@ -135,39 +126,17 @@
         if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
         if (DEBUG) logLayoutTransition();
 
-        MotionEvent cancellation = MotionEvent.obtain(ev);
-        cancellation.setAction(MotionEvent.ACTION_CANCEL);
-
-        if (mSwipeHelper.onInterceptTouchEvent(ev)) {
-            if (DEBUG) Log.v(TAG, "will swipe");
-            mCurrentHelper = mSwipeHelper;
-            mExpandHelper.onInterceptTouchEvent(cancellation);
-            return true;
-        } else if (mExpandHelper.onInterceptTouchEvent(ev)) {
-            if (DEBUG) Log.v(TAG, "will stretch");
-            mCurrentHelper = mExpandHelper;
-            mSwipeHelper.onInterceptTouchEvent(cancellation);
-            return true;
-        } else {
-            mCurrentHelper = null;
-            if (super.onInterceptTouchEvent(ev)) {
-                if (DEBUG) Log.v(TAG, "intercepting ourselves");
-                mSwipeHelper.onInterceptTouchEvent(cancellation);
-                mExpandHelper.onInterceptTouchEvent(cancellation);
-                return true;
-            }
-        }
-        return false;
+        return mSwipeHelper.onInterceptTouchEvent(ev) ||
+                super.onInterceptTouchEvent(ev);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.v(TAG, "onTouchEvent()");
         if (DEBUG) logLayoutTransition();
-        if (mCurrentHelper != null) {
-            return mCurrentHelper.onTouchEvent(ev);
-        }
-        return super.onTouchEvent(ev);
+
+        return mSwipeHelper.onTouchEvent(ev) ||
+                super.onTouchEvent(ev);
     }
 
     public boolean canChildBeDismissed(View v) {
@@ -202,6 +171,13 @@
     public View getChildAtPosition(MotionEvent ev) {
         return getChildAtPosition(ev.getX(), ev.getY());
     }
+
+    public View getChildAtRawPosition(float touchX, float touchY) {
+        int[] location = new int[2];
+        getLocationOnScreen(location);
+        return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1]));
+    }
+
     public View getChildAtPosition(float touchX, float touchY) {
         // find the view under the pointer, accounting for GONE views
         final int count = getChildCount();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 9ca83e6..46ea940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -75,6 +75,7 @@
         super.onDetachedFromWindow();
         mAirplane.release();
         mDoNotDisturb.release();
+        mRotate.release();
     }
 
     public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index dba1606..c627d47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -188,6 +188,17 @@
 
     public Context getContext() { return mContext; }
 
+    private View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
+        public boolean onTouch(View v, MotionEvent event) {
+            switch(event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    showSearchPanel();
+                break;
+            }
+            return false;
+        }
+    };
+
     @Override
     protected void createAndAddWindows() {
         addStatusBarWindow();
@@ -290,6 +301,7 @@
 
         // Search Panel
         mStatusBarView.setBar(this);
+        mHomeButton.setOnTouchListener(mHomeSearchActionListener);
         updateSearchPanel();
 
         // Input methods Panel
@@ -1001,6 +1013,8 @@
         mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
         mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
         mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
+        mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
+        mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
     }
 
     @Override // CommandQueue
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index a6fc396..30d49ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.tablet;
 
+import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.DelegateViewHelper;
 
@@ -37,8 +38,7 @@
     private DelegateViewHelper mDelegateHelper;
 
     public TabletStatusBarView(Context context) {
-        super(context);
-        mDelegateHelper = new DelegateViewHelper(this);
+        this(context, null);
     }
 
     public TabletStatusBarView(Context context, AttributeSet attrs) {
@@ -55,6 +55,28 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mDelegateHelper != null) {
+            mDelegateHelper.onInterceptTouchEvent(event);
+        }
+        return true;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        // Find the view we wish to grab events from in order to detect search gesture.
+        // Depending on the device, this will be one of the id's listed below.
+        // If we don't find one, we'll use the view provided in the constructor above (this view).
+        View view = findViewById(R.id.navigationArea);
+        if (view == null) {
+            view = findViewById(R.id.nav_buttons);
+        }
+        mDelegateHelper.setSourceView(view);
+        mDelegateHelper.setInitialTouchRegion(view);
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             if (TabletStatusBar.DEBUG) {
@@ -86,8 +108,8 @@
         if (TabletStatusBar.DEBUG) {
             Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
         }
-        if (mDelegateHelper != null) {
-            return mDelegateHelper.onInterceptTouchEvent(ev);
+        if (mDelegateHelper != null && mDelegateHelper.onInterceptTouchEvent(ev)) {
+            return true;
         }
         return super.onInterceptTouchEvent(ev);
     }
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index c46b94a..737ea47 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -300,7 +300,18 @@
      * onServiceConnected() callback is received.
      */
     void handleServiceConnected() {
-        if (DEBUG) Log.d(TAG, "handleServiceConnected()");
+        Log.d(TAG, "handleServiceConnected()");
+
+        // It is possible that an unbind has occurred in the time between the bind and when this
+        // function is reached.  If an unbind has already occurred, proceeding on to call startUi()
+        // can result in a fatal error.  Note that the onServiceConnected() callback is
+        // asynchronous, so this possibility would still exist if we executed this directly in
+        // onServiceConnected() rather than using a handler.
+        if (!mBoundToService) {
+            Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
+            return;
+        }
+
         try {
             mService.registerCallback(mFaceUnlockCallback);
         } catch (RemoteException e) {
@@ -452,25 +463,12 @@
      * Tells the Face Unlock service to start displaying its UI and start processing.
      */
     private void startUi(IBinder windowToken, int x, int y, int w, int h) {
-        Log.d(TAG, "startUi()");
+        if (DEBUG) Log.d(TAG, "startUi()");
         synchronized (mServiceRunningLock) {
             if (!mServiceRunning) {
-                if (DEBUG) Log.d(TAG, "Starting Face Unlock");
+                Log.d(TAG, "Starting Face Unlock");
                 try {
-                    // TODO: these checks and logs are for tracking down bug 6409767 and can be
-                    // removed when that bug is fixed.
-                    if (mService == null) {
-                        Log.d(TAG, "mService is null");
-                    }
-                    if (windowToken == null) {
-                        Log.d(TAG, "windowToken is null");
-                    }
-                    if (mLockPatternUtils == null) {
-                        Log.d(TAG, "mLockPatternUtils is null");
-                    }
-                    Log.d(TAG, "x,y,w,h,live: " + x + "," + y + "," + w + "," + h + ", no");
                     mService.startUi(windowToken, x, y, w, h, false);
-                    Log.d(TAG, "mService.startUi() called");
                 } catch (RemoteException e) {
                     Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
                     return;
@@ -492,7 +490,7 @@
         // screen is turned off.  That's why we check.
         synchronized (mServiceRunningLock) {
             if (mServiceRunning) {
-                if (DEBUG) Log.d(TAG, "Stopping Face Unlock");
+                Log.d(TAG, "Stopping Face Unlock");
                 try {
                     mService.stopUi();
                 } catch (RemoteException e) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 7f432bf..504bb63 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -117,7 +117,6 @@
             final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
             int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
                     | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
-                    | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
                     | WindowManager.LayoutParams.FLAG_SLIPPERY
                     /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 8ea334e..30cb530 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -32,6 +32,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Vibrator;
@@ -45,7 +46,6 @@
 import android.media.AudioManager;
 import android.os.RemoteException;
 import android.provider.MediaStore;
-import android.provider.Settings;
 
 import java.io.File;
 
@@ -252,13 +252,19 @@
         }
     }
 
+    // This code should be the same as that in SearchPanelView
+    public boolean isAssistantAvailable() {
+        Intent intent = getAssistIntent();
+        return intent == null ? false
+                : mContext.getPackageManager().queryIntentActivities(intent,
+                        PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+    }
+
     private Intent getAssistIntent() {
         Intent intent = null;
-        if (mSearchManager == null) {
-            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        }
-        if (mSearchManager != null) {
-            ComponentName globalSearchActivity = mSearchManager.getGlobalSearchActivity();
+        SearchManager searchManager = getSearchManager();
+        if (searchManager != null) {
+            ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
             if (globalSearchActivity != null) {
                 intent = new Intent(Intent.ACTION_ASSIST);
                 intent.setPackage(globalSearchActivity.getPackageName());
@@ -271,6 +277,13 @@
         return intent;
     }
 
+    private SearchManager getSearchManager() {
+        if (mSearchManager == null) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        }
+        return mSearchManager;
+    }
+
     class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
             UnlockWidgetCommonMethods {
         private final MultiWaveView mMultiWaveView;
@@ -388,6 +401,10 @@
         public void cleanUp() {
             mMultiWaveView.setOnTriggerListener(null);
         }
+
+        public void onFinishFinalAnimation() {
+
+        }
     }
 
     private void requestUnlockScreen() {
@@ -517,14 +534,12 @@
                         .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_search)
                         : false;
 
-        // TODO: test to see if search is available
-        boolean searchActionAvailable = true;
-
         if (disabledByAdmin) {
             Log.v(TAG, "Camera disabled by Device Policy");
         } else if (disabledBySimState) {
             Log.v(TAG, "Camera disabled by Sim State");
         }
+        boolean searchActionAvailable = isAssistantAvailable();
         mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
         mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
         mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 17e671d..9a6d2cc 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -41,7 +41,7 @@
 class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
         implements KeyguardScreen {
 
-    private static final boolean DEBUG = true; /* TODO: revert before JB release */
+    private static final boolean DEBUG = false;
     private static final String TAG = "UnlockScreen";
 
     // how long before we clear the wrong pattern
@@ -321,7 +321,6 @@
             implements LockPatternView.OnPatternListener {
 
         public void onPatternStart() {
-            if (DEBUG) Log.d(TAG, "Got pattern start");
             mLockPatternView.removeCallbacks(mCancelPatternRunnable);
         }
 
@@ -337,7 +336,6 @@
                 // Give just a little extra time if they hit one of the first few dots
                 mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS);
             }
-            if (DEBUG) Log.d(TAG, "Got pattern cell");
         }
 
         public void onPatternDetected(List<LockPatternView.Cell> pattern) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 9629f0a..47703c6 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1630,7 +1630,12 @@
         if (mActionBar != null) {
             SparseArray<Parcelable> actionBarStates =
                     savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
-            mActionBar.restoreHierarchyState(actionBarStates);
+            if (actionBarStates != null) {
+                mActionBar.restoreHierarchyState(actionBarStates);
+            } else {
+                Log.w(TAG, "Missing saved instance states for action bar views! " +
+                        "State will not be restored.");
+            }
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 3147ba7..a99ae26 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -33,6 +33,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -158,7 +159,7 @@
     static final boolean DEBUG = false;
     static final boolean localLOGV = false;
     static final boolean DEBUG_LAYOUT = false;
-    static final boolean DEBUG_FALLBACK = false;
+    static final boolean DEBUG_INPUT = false;
     static final boolean SHOW_STARTING_ANIMATIONS = true;
     static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
 
@@ -179,7 +180,6 @@
     static final int LONG_PRESS_HOME_NOTHING = 0;
     static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
     static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
-    static final int LONG_PRESS_HOME_VOICE_SEARCH = 3;
 
     // wallpaper is at the bottom, though the window manager may move it.
     static final int WALLPAPER_LAYER = 2;
@@ -322,10 +322,12 @@
 
     static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
     static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
-    static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2;
+    static final int RECENT_APPS_BEHAVIOR_DISMISS = 2;
+    static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 3;
 
     RecentApplicationsDialog mRecentAppsDialog;
     int mRecentAppsDialogHeldModifiers;
+    boolean mLanguageSwitchKeyPressed;
 
     int mLidState = LID_ABSENT;
     boolean mHaveBuiltInKeyboard;
@@ -410,6 +412,10 @@
     int mSystemLeft, mSystemTop, mSystemRight, mSystemBottom;
     // For applications requesting stable content insets, these are them.
     int mStableLeft, mStableTop, mStableRight, mStableBottom;
+    // For applications requesting stable content insets but have also set the
+    // fullscreen window flag, these are the stable dimensions without the status bar.
+    int mStableFullscreenLeft, mStableFullscreenTop;
+    int mStableFullscreenRight, mStableFullscreenBottom;
     // During layout, the current screen borders with all outer decoration
     // (status bar, input method dock) accounted for.
     int mCurLeft, mCurTop, mCurRight, mCurBottom;
@@ -500,6 +506,7 @@
 
     ShortcutManager mShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
+    boolean mHavePendingMediaKeyRepeatWithWakeLock;
 
     // Fallback actions by key code.
     private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
@@ -507,6 +514,8 @@
 
     private static final int MSG_ENABLE_POINTER_LOCATION = 1;
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
+    private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
+    private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -518,6 +527,12 @@
                 case MSG_DISABLE_POINTER_LOCATION:
                     disablePointerLocation();
                     break;
+                case MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK:
+                    dispatchMediaKeyWithWakeLock((KeyEvent)msg.obj);
+                    break;
+                case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
+                    dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
+                    break;
             }
         }
     }
@@ -758,9 +773,6 @@
                     mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
                 mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
             }
-            if (hasNavigationBar()) {
-                mLongPressOnHomeBehavior = LONG_PRESS_HOME_VOICE_SEARCH;
-            }
         }
 
         if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
@@ -780,18 +792,6 @@
             } catch (RemoteException e) {
                 Slog.e(TAG, "RemoteException when showing recent apps", e);
             }
-        } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_VOICE_SEARCH) {
-            Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
-            try {
-                intent.setFlags(
-                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivity(intent);
-            } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "Unable to launch. tag=" + TAG + " intent=" + intent, e);
-            } catch (SecurityException e) {
-                Log.e(TAG, "PhoneWindowManager does not have the permission to launch " +
-                      "tag=" + TAG + " intent=" + intent, e);
-            }
         }
     }
 
@@ -809,6 +809,7 @@
                 if (mRecentAppsDialog.isShowing()) {
                     switch (behavior) {
                         case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
+                        case RECENT_APPS_BEHAVIOR_DISMISS:
                             mRecentAppsDialog.dismiss();
                             break;
                         case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
@@ -830,6 +831,7 @@
                             }
                             mRecentAppsDialog.show();
                             break;
+                        case RECENT_APPS_BEHAVIOR_DISMISS:
                         case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
                         default:
                             break;
@@ -1433,8 +1435,9 @@
                 && attrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                 && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
     }
-    
+
     /** {@inheritDoc} */
+    @Override
     public View addStartingWindow(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int windowFlags) {
@@ -1444,7 +1447,7 @@
         if (packageName == null) {
             return null;
         }
-        
+
         try {
             Context context = mContext;
             //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
@@ -1457,16 +1460,19 @@
                     // Ignore
                 }
             }
-            
+
             Window win = PolicyManager.makeNewWindow(context);
-            if (win.getWindowStyle().getBoolean(
-                    com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
+            final TypedArray ta = win.getWindowStyle();
+            if (ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowDisablePreview, false)
+                || ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {
                 return null;
             }
-            
+
             Resources r = context.getResources();
             win.setTitle(r.getText(labelRes, nonLocalizedLabel));
-    
+
             win.setType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
             // Force the window flags: this is a fake window, so it is not really
@@ -1482,14 +1488,14 @@
                 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-    
+
             if (!compatInfo.supportsScreen()) {
                 win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
             }
 
             win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                     WindowManager.LayoutParams.MATCH_PARENT);
-    
+
             final WindowManager.LayoutParams params = win.getAttributes();
             params.token = appToken;
             params.packageName = packageName;
@@ -1511,7 +1517,7 @@
                 // earlier.)
                 return null;
             }
-            
+
             if (localLOGV) Log.v(
                 TAG, "Adding starting window for " + packageName
                 + " / " + appToken + ": "
@@ -1701,7 +1707,7 @@
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
 
-        if (false) {
+        if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
                     + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
                     + " canceled=" + canceled);
@@ -1849,7 +1855,7 @@
             }
             return 0;
         } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
-            if (down && repeatCount == 0) {
+            if (down && repeatCount == 0 && !keyguardOn) {
                 showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
             }
             return -1;
@@ -1886,27 +1892,29 @@
         }
 
         // Invoke shortcuts using Meta.
-        if (down && repeatCount == 0
+        if (down && repeatCount == 0 && !keyguardOn
                 && (metaState & KeyEvent.META_META_ON) != 0) {
             final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
-                    metaState & ~(KeyEvent.META_META_ON
-                            | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
-            if (shortcutIntent != null) {
-                shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                try {
-                    mContext.startActivity(shortcutIntent);
-                } catch (ActivityNotFoundException ex) {
-                    Slog.w(TAG, "Dropping shortcut key combination because "
-                            + "the activity to which it is registered was not found: "
-                            + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+            if (kcm.isPrintingKey(keyCode)) {
+                Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+                        metaState & ~(KeyEvent.META_META_ON
+                                | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+                if (shortcutIntent != null) {
+                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    try {
+                        mContext.startActivity(shortcutIntent);
+                    } catch (ActivityNotFoundException ex) {
+                        Slog.w(TAG, "Dropping shortcut key combination because "
+                                + "the activity to which it is registered was not found: "
+                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+                    }
+                    return -1;
                 }
-                return -1;
             }
         }
 
         // Handle application launch keys.
-        if (down && repeatCount == 0) {
+        if (down && repeatCount == 0 && !keyguardOn) {
             String category = sApplicationLaunchKeyCategories.get(keyCode);
             if (category != null) {
                 Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
@@ -1924,7 +1932,7 @@
 
         // Display task switcher for ALT-TAB or Meta-TAB.
         if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
-            if (mRecentAppsDialogHeldModifiers == 0) {
+            if (mRecentAppsDialogHeldModifiers == 0 && !keyguardOn) {
                 final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
                 if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
                         || KeyEvent.metaStateHasModifiers(
@@ -1937,7 +1945,24 @@
         } else if (!down && mRecentAppsDialogHeldModifiers != 0
                 && (metaState & mRecentAppsDialogHeldModifiers) == 0) {
             mRecentAppsDialogHeldModifiers = 0;
-            showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+            showOrHideRecentAppsDialog(keyguardOn ? RECENT_APPS_BEHAVIOR_DISMISS :
+                    RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+        }
+
+        // Handle keyboard language switching.
+        if (down && repeatCount == 0
+                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
+                        || (keyCode == KeyEvent.KEYCODE_SPACE
+                                && (metaState & KeyEvent.META_CTRL_MASK) != 0))) {
+            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+            return -1;
+        }
+        if (mLanguageSwitchKeyPressed && !down
+                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
+                        || keyCode == KeyEvent.KEYCODE_SPACE)) {
+            mLanguageSwitchKeyPressed = false;
+            return -1;
         }
 
         // Let the application handle the key.
@@ -1948,7 +1973,7 @@
     @Override
     public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
         // Note: This method is only called if the initial down was unhandled.
-        if (DEBUG_FALLBACK) {
+        if (DEBUG_INPUT) {
             Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
                     + ", flags=" + event.getFlags()
                     + ", keyCode=" + event.getKeyCode()
@@ -1975,7 +2000,7 @@
             }
 
             if (fallbackAction != null) {
-                if (DEBUG_FALLBACK) {
+                if (DEBUG_INPUT) {
                     Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode
                             + " metaState=" + Integer.toHexString(fallbackAction.metaState));
                 }
@@ -2002,7 +2027,7 @@
             }
         }
 
-        if (DEBUG_FALLBACK) {
+        if (DEBUG_INPUT) {
             if (fallbackEvent == null) {
                 Slog.d(TAG, "No fallback.");
             } else {
@@ -2153,22 +2178,31 @@
 
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
         final int fl = attrs.flags;
+        final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
 
-        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
+        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
                 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
             int availRight, availBottom;
             if (mCanHideNavigationBar &&
-                    (attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+                    (systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
                 availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                 availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
             } else {
                 availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
                 availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
             }
-            if ((attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-                contentInset.set(mStableLeft, mStableTop,
-                        availRight - mStableRight, availBottom - mStableBottom);
-            } else if ((attrs.systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
+            if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+                if ((fl & FLAG_FULLSCREEN) != 0) {
+                    contentInset.set(mStableFullscreenLeft, mStableFullscreenTop,
+                            availRight - mStableFullscreenRight,
+                            availBottom - mStableFullscreenBottom);
+                } else {
+                    contentInset.set(mStableLeft, mStableTop,
+                            availRight - mStableRight, availBottom - mStableBottom);
+                }
+            } else if ((fl & FLAG_FULLSCREEN) != 0) {
+                contentInset.setEmpty();
+            } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
                         | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
                 contentInset.set(mCurLeft, mCurTop,
                         availRight - mCurRight, availBottom - mCurBottom);
@@ -2189,10 +2223,14 @@
         mRestrictedScreenLeft = mRestrictedScreenTop = 0;
         mRestrictedScreenWidth = displayWidth;
         mRestrictedScreenHeight = displayHeight;
-        mDockLeft = mContentLeft = mStableLeft = mSystemLeft = mCurLeft = 0;
-        mDockTop = mContentTop = mStableTop = mSystemTop = mCurTop = 0;
-        mDockRight = mContentRight = mStableRight = mSystemRight = mCurRight = displayWidth;
-        mDockBottom = mContentBottom = mStableBottom = mSystemBottom = mCurBottom = displayHeight;
+        mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
+                = mSystemLeft = mCurLeft = 0;
+        mDockTop = mContentTop = mStableTop = mStableFullscreenTop
+                = mSystemTop = mCurTop = 0;
+        mDockRight = mContentRight = mStableRight = mStableFullscreenRight
+                = mSystemRight = mCurRight = displayWidth;
+        mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
+                = mSystemBottom = mCurBottom = displayHeight;
         mDockLayer = 0x10000000;
         mStatusBarLayer = -1;
 
@@ -2245,7 +2283,7 @@
                     }
                 }
                 mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
-                mStableBottom = mTmpNavigationFrame.top;
+                mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
                 if (navVisible) {
                     mNavigationBar.showLw(true);
                     mDockBottom = mTmpNavigationFrame.top;
@@ -2269,7 +2307,7 @@
                     }
                 }
                 mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
-                mStableRight = mTmpNavigationFrame.left;
+                mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
                 if (navVisible) {
                     mNavigationBar.showLw(true);
                     mDockRight = mTmpNavigationFrame.left;
@@ -2407,7 +2445,25 @@
         pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
                 ? attached.getFrameLw() : df);
     }
-    
+
+    private void applyStableConstraints(int sysui, int fl, Rect r) {
+        if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+            // If app is requesting a stable layout, don't let the
+            // content insets go below the stable values.
+            if ((fl & FLAG_FULLSCREEN) != 0) {
+                if (r.left < mStableFullscreenLeft) r.left = mStableFullscreenLeft;
+                if (r.top < mStableFullscreenTop) r.top = mStableFullscreenTop;
+                if (r.right > mStableFullscreenRight) r.right = mStableFullscreenRight;
+                if (r.bottom > mStableFullscreenBottom) r.bottom = mStableFullscreenBottom;
+            } else {
+                if (r.left < mStableLeft) r.left = mStableLeft;
+                if (r.top < mStableTop) r.top = mStableTop;
+                if (r.right > mStableRight) r.right = mStableRight;
+                if (r.bottom > mStableBottom) r.bottom = mStableBottom;
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
             WindowState attached) {
@@ -2514,14 +2570,7 @@
                         cf.right = mContentRight;
                         cf.bottom = mContentBottom;
                     }
-                    if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-                        // If app is requesting a stable layout, don't let the
-                        // content insets go below the stable values.
-                        if (cf.left < mStableLeft) cf.left = mStableLeft;
-                        if (cf.top < mStableTop) cf.top = mStableTop;
-                        if (cf.right > mStableRight) cf.right = mStableRight;
-                        if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
-                    }
+                    applyStableConstraints(sysUiFl, fl, cf);
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.left = mCurLeft;
                         vf.top = mCurTop;
@@ -2603,14 +2652,7 @@
                     pf.bottom = df.bottom = cf.bottom
                             = mRestrictedScreenTop+mRestrictedScreenHeight;
                 }
-                if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-                    // If app is requesting a stable layout, don't let the
-                    // content insets go below the stable values.
-                    if (cf.left < mStableLeft) cf.left = mStableLeft;
-                    if (cf.top < mStableTop) cf.top = mStableTop;
-                    if (cf.right > mStableRight) cf.right = mStableRight;
-                    if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
-                }
+                applyStableConstraints(sysUiFl, fl, cf);
                 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                     vf.left = mCurLeft;
                     vf.top = mCurTop;
@@ -3078,7 +3120,7 @@
             return 0;
         }
 
-        if (false) {
+        if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
                   + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
@@ -3300,8 +3342,13 @@
                     // Only do this if we would otherwise not pass it to the user. In that
                     // case, the PhoneWindow class will do the same thing, except it will
                     // only do it if the showing app doesn't process the key on its own.
+                    // Note that we need to make a copy of the key event here because the
+                    // original key event will be recycled when we return.
                     mBroadcastWakeLock.acquire();
-                    mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
+                    Message msg = mHandler.obtainMessage(MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
+                            new KeyEvent(event));
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
                 }
                 break;
             }
@@ -3350,24 +3397,58 @@
         return result;
     }
 
-    class PassHeadsetKey implements Runnable {
-        KeyEvent mKeyEvent;
-
-        PassHeadsetKey(KeyEvent keyEvent) {
-            mKeyEvent = keyEvent;
+    void dispatchMediaKeyWithWakeLock(KeyEvent event) {
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
         }
 
-        public void run() {
-            if (ActivityManagerNative.isSystemReady()) {
-                IAudioService audioService = getAudioService();
-                if (audioService != null) {
-                    try {
-                        audioService.dispatchMediaKeyEventUnderWakelock(mKeyEvent);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
-                    }
+        if (mHavePendingMediaKeyRepeatWithWakeLock) {
+            if (DEBUG_INPUT) {
+                Slog.d(TAG, "dispatchMediaKeyWithWakeLock: canceled repeat");
+            }
+
+            mHandler.removeMessages(MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK);
+            mHavePendingMediaKeyRepeatWithWakeLock = false;
+            mBroadcastWakeLock.release(); // pending repeat was holding onto the wake lock
+        }
+
+        dispatchMediaKeyWithWakeLockToAudioService(event);
+
+        if (event.getAction() == KeyEvent.ACTION_DOWN
+                && event.getRepeatCount() == 0) {
+            mHavePendingMediaKeyRepeatWithWakeLock = true;
+
+            Message msg = mHandler.obtainMessage(
+                    MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK, event);
+            msg.setAsynchronous(true);
+            mHandler.sendMessageDelayed(msg, ViewConfiguration.getKeyRepeatTimeout());
+        } else {
+            mBroadcastWakeLock.release();
+        }
+    }
+
+    void dispatchMediaKeyRepeatWithWakeLock(KeyEvent event) {
+        mHavePendingMediaKeyRepeatWithWakeLock = false;
+
+        KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(event,
+                SystemClock.uptimeMillis(), 1, event.getFlags() | KeyEvent.FLAG_LONG_PRESS);
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "dispatchMediaKeyRepeatWithWakeLock: " + repeatEvent);
+        }
+
+        dispatchMediaKeyWithWakeLockToAudioService(repeatEvent);
+        mBroadcastWakeLock.release();
+    }
+
+    void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
+        if (ActivityManagerNative.isSystemReady()) {
+            IAudioService audioService = getAudioService();
+            if (audioService != null) {
+                try {
+                    audioService.dispatchMediaKeyEventUnderWakelock(event);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
                 }
-                mBroadcastWakeLock.release();
             }
         }
     }
@@ -3425,6 +3506,10 @@
         }
         if (screenOnListener != null) {
             if (mKeyguardMediator != null) {
+                try {
+                    mWindowManager.setEventDispatching(true);
+                } catch (RemoteException unhandled) {
+                }
                 mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
                     @Override public void onShown(IBinder windowToken) {
                         if (windowToken != null) {
@@ -4258,6 +4343,10 @@
                 pw.print(","); pw.print(mRestrictedScreenTop);
                 pw.print(") "); pw.print(mRestrictedScreenWidth);
                 pw.print("x"); pw.println(mRestrictedScreenHeight);
+        pw.print(prefix); pw.print("mStableFullscreen=("); pw.print(mStableFullscreenLeft);
+                pw.print(","); pw.print(mStableFullscreenTop);
+                pw.print(")-("); pw.print(mStableFullscreenRight);
+                pw.print(","); pw.print(mStableFullscreenBottom); pw.println(")");
         pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
                 pw.print(","); pw.print(mStableTop);
                 pw.print(")-("); pw.print(mStableRight);
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 50bfee6..f80ac18 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "EventHub"
 
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 
 #include "EventHub.h"
 
@@ -767,7 +767,11 @@
                     size_t count = size_t(readSize) / sizeof(struct input_event);
                     for (size_t i = 0; i < count; i++) {
                         const struct input_event& iev = readBuffer[i];
-                        nsecs_t delta = 0; 
+                        ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
+                                device->path.string(),
+                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+                                iev.type, iev.code, iev.value);
+
 #ifdef HAVE_POSIX_CLOCKS
                         // Use the time specified in the event instead of the current time
                         // so that downstream code can get more accurate estimates of
@@ -782,23 +786,10 @@
                         // system call that also queries ktime_get_ts().
                         event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                                 + nsecs_t(iev.time.tv_usec) * 1000LL;
-                        delta = now - event->when;
-
-                        // Only log verbose if events are older that 1ms
-                        if (delta > 1 * 1000000LL) {
-                            ALOGV("event time %lld, now %lld, delta %lldus", event->when, now, delta / 1000LL);
-                        }
+                        ALOGV("event time %lld, now %lld", event->when, now);
 #else
                         event->when = now;
 #endif
-                        if (delta > 1 * 1000000LL) {
-                            ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
-                                  device->path.string(),
-                                  (int) iev.time.tv_sec, (int) iev.time.tv_usec,
-                                  iev.type, iev.code, iev.value);
-                        }
-
-
                         event->deviceId = deviceId;
                         event->type = iev.type;
                         event->code = iev.code;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 1062d68..c8e11c2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -1226,27 +1226,36 @@
             isSplit = true;
         } else if (isSplit) {
             // New window does not support splitting but we have already split events.
-            // Assign the pointer to the first foreground window we find.
-            // (May be NULL which is why we put this code block before the next check.)
-            newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
+            // Ignore the new window.
+            newTouchedWindowHandle = NULL;
         }
 
-        // If we did not find a touched window then fail.
+        // Handle the case where we did not find a window.
         if (newTouchedWindowHandle == NULL) {
-            if (mFocusedApplicationHandle != NULL) {
+            // Try to assign the pointer to the first foreground window we find, if there is one.
+            newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
+            if (newTouchedWindowHandle == NULL) {
+                // There is no touched window.  If this is an initial down event
+                // then wait for a window to appear that will handle the touch.  This is
+                // to ensure that we report an ANR in the case where an application has started
+                // but not yet put up a window and the user is starting to get impatient.
+                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
+                        && mFocusedApplicationHandle != NULL) {
 #if DEBUG_FOCUS
-                ALOGD("Waiting because there is no touched window but there is a "
-                        "focused application that may eventually add a new window: %s.",
-                        getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
+                    ALOGD("Waiting because there is no touched window but there is a "
+                            "focused application that may eventually add a new window: %s.",
+                            getApplicationWindowLabelLocked(
+                                    mFocusedApplicationHandle, NULL).string());
 #endif
-                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        mFocusedApplicationHandle, NULL, nextWakeupTime);
-                goto Unresponsive;
-            }
+                    injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
+                            mFocusedApplicationHandle, NULL, nextWakeupTime);
+                    goto Unresponsive;
+                }
 
-            ALOGI("Dropping event because there is no touched window or focused application.");
-            injectionResult = INPUT_EVENT_INJECTION_FAILED;
-            goto Failed;
+                ALOGI("Dropping event because there is no touched window.");
+                injectionResult = INPUT_EVENT_INJECTION_FAILED;
+                goto Failed;
+            }
         }
 
         // Set target flags.
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 23f2fdd..df2e1aa 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 import android.util.Xml;
+import android.view.WindowManager;
 import android.widget.RemoteViews;
 
 import com.android.internal.appwidget.IAppWidgetHost;
@@ -171,6 +172,7 @@
     boolean mSafeMode;
     int mUserId;
     boolean mStateLoaded;
+    int mMaxWidgetBitmapMemory;
 
     // These are for debugging only -- widgets are going missing in some rare instances
     ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
@@ -181,6 +183,14 @@
         mPm = AppGlobals.getPackageManager();
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserId = userId;
+        computeMaximumWidgetBitmapMemory();
+    }
+
+    void computeMaximumWidgetBitmapMemory() {
+        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        int height = wm.getDefaultDisplay().getRawHeight();
+        int width = wm.getDefaultDisplay().getRawWidth();
+        mMaxWidgetBitmapMemory = 4 * width * height;
     }
 
     public void systemReady(boolean safeMode) {
@@ -806,6 +816,15 @@
         if (appWidgetIds == null) {
             return;
         }
+
+        int bitmapMemoryUsage = views.estimateMemoryUsage();
+        if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
+            throw new IllegalArgumentException("RemoteViews for widget update exceeds maximum" +
+                    " bitmap memory usage (used: " + bitmapMemoryUsage + ", max: " +
+                    mMaxWidgetBitmapMemory + ") The total memory cannot exceed that required to" +
+                    " fill the device's screen once.");
+        }
+
         if (appWidgetIds.length == 0) {
             return;
         }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a3768c6..2167c49 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -48,6 +48,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -252,6 +253,34 @@
     IBackupTransport mLocalTransport, mGoogleTransport;
     ActiveRestoreSession mActiveRestoreSession;
 
+    // Watch the device provisioning operation during setup
+    ContentObserver mProvisionedObserver;
+
+    class ProvisionedObserver extends ContentObserver {
+        public ProvisionedObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void onChange(boolean selfChange) {
+            final boolean wasProvisioned = mProvisioned;
+            final boolean isProvisioned = deviceIsProvisioned();
+            // latch: never unprovision
+            mProvisioned = wasProvisioned || isProvisioned;
+            if (MORE_DEBUG) {
+                Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
+                        + " is=" + isProvisioned + " now=" + mProvisioned);
+            }
+
+            synchronized (mQueueLock) {
+                if (mProvisioned && !wasProvisioned && mEnabled) {
+                    // we're now good to go, so start the backup alarms
+                    if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
+                    startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+                }
+            }
+        }
+    }
+
     class RestoreGetSetsParams {
         public IBackupTransport transport;
         public ActiveRestoreSession session;
@@ -695,12 +724,19 @@
         mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
 
         // Set up our bookkeeping
-        boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
+        final ContentResolver resolver = context.getContentResolver();
+        boolean areEnabled = Settings.Secure.getInt(resolver,
                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
-        mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
-        mAutoRestore = Settings.Secure.getInt(context.getContentResolver(),
+        mProvisioned = Settings.Secure.getInt(resolver,
+                Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
+        mAutoRestore = Settings.Secure.getInt(resolver,
                 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
+
+        mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
+        resolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED),
+                false, mProvisionedObserver);
+
         // If Encrypted file systems is enabled or disabled, this call will return the
         // correct directory.
         mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
@@ -5172,24 +5208,9 @@
     public void setBackupProvisioned(boolean available) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupProvisioned");
-
-        boolean wasProvisioned = mProvisioned;
-        synchronized (this) {
-            Settings.Secure.putInt(mContext.getContentResolver(),
-                    Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
-            mProvisioned = available;
-        }
-
-        synchronized (mQueueLock) {
-            if (available && !wasProvisioned && mEnabled) {
-                // we're now good to go, so start the backup alarms
-                startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
-            } else if (!available) {
-                // No longer enabled, so stop running backups
-                Slog.w(TAG, "Backup service no longer provisioned");
-                mAlarmManager.cancel(mRunBackupIntent);
-            }
-        }
+        /*
+         * This is now a no-op; provisioning is simply the device's own setup state.
+         */
     }
 
     private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index e396a69..7bbc8b5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -66,6 +66,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -995,120 +996,136 @@
     // javadoc from interface
     public int startUsingNetworkFeature(int networkType, String feature,
             IBinder binder) {
+        long startTime = 0;
+        if (DBG) {
+            startTime = SystemClock.elapsedRealtime();
+        }
         if (VDBG) {
             log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
                     + Binder.getCallingUid());
         }
         enforceChangePermission();
-        if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
-                mNetConfigs[networkType] == null) {
-            return Phone.APN_REQUEST_FAILED;
-        }
+        try {
+            if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
+                    mNetConfigs[networkType] == null) {
+                return Phone.APN_REQUEST_FAILED;
+            }
 
-        FeatureUser f = new FeatureUser(networkType, feature, binder);
+            FeatureUser f = new FeatureUser(networkType, feature, binder);
 
-        // TODO - move this into individual networktrackers
-        int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
+            // TODO - move this into individual networktrackers
+            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
 
-        if (mProtectedNetworks.contains(usedNetworkType)) {
-            enforceConnectivityInternalPermission();
-        }
+            if (mProtectedNetworks.contains(usedNetworkType)) {
+                enforceConnectivityInternalPermission();
+            }
 
-        // if UID is restricted, don't allow them to bring up metered APNs
-        final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
-        final int uidRules;
-        synchronized (mRulesLock) {
-            uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
-        }
-        if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
-            return Phone.APN_REQUEST_FAILED;
-        }
+            // if UID is restricted, don't allow them to bring up metered APNs
+            final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
+            final int uidRules;
+            synchronized (mRulesLock) {
+                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
+            }
+            if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
+                return Phone.APN_REQUEST_FAILED;
+            }
 
-        NetworkStateTracker network = mNetTrackers[usedNetworkType];
-        if (network != null) {
-            Integer currentPid = new Integer(getCallingPid());
-            if (usedNetworkType != networkType) {
-                NetworkInfo ni = network.getNetworkInfo();
+            NetworkStateTracker network = mNetTrackers[usedNetworkType];
+            if (network != null) {
+                Integer currentPid = new Integer(getCallingPid());
+                if (usedNetworkType != networkType) {
+                    NetworkInfo ni = network.getNetworkInfo();
 
-                if (ni.isAvailable() == false) {
-                    if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
-                        if (DBG) log("special network not available ni=" + ni.getTypeName());
-                        return Phone.APN_TYPE_NOT_AVAILABLE;
-                    } else {
-                        // else make the attempt anyway - probably giving REQUEST_STARTED below
-                        if (DBG) {
-                            log("special network not available, but try anyway ni=" +
-                                    ni.getTypeName());
-                        }
-                    }
-                }
-
-                int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
-
-                synchronized(this) {
-                    boolean addToList = true;
-                    if (restoreTimer < 0) {
-                        // In case there is no timer is specified for the feature,
-                        // make sure we don't add duplicate entry with the same request.
-                        for (FeatureUser u : mFeatureUsers) {
-                            if (u.isSameUser(f)) {
-                                // Duplicate user is found. Do not add.
-                                addToList = false;
-                                break;
+                    if (ni.isAvailable() == false) {
+                        if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+                            if (DBG) log("special network not available ni=" + ni.getTypeName());
+                            return Phone.APN_TYPE_NOT_AVAILABLE;
+                        } else {
+                            // else make the attempt anyway - probably giving REQUEST_STARTED below
+                            if (DBG) {
+                                log("special network not available, but try anyway ni=" +
+                                        ni.getTypeName());
                             }
                         }
                     }
 
-                    if (addToList) mFeatureUsers.add(f);
-                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
-                        // this gets used for per-pid dns when connected
-                        mNetRequestersPids[usedNetworkType].add(currentPid);
-                    }
-                }
+                    int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
 
-                if (restoreTimer >= 0) {
-                    mHandler.sendMessageDelayed(
-                            mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
-                }
-
-                if ((ni.isConnectedOrConnecting() == true) &&
-                        !network.isTeardownRequested()) {
-                    if (ni.isConnected() == true) {
-                        final long token = Binder.clearCallingIdentity();
-                        try {
-                            // add the pid-specific dns
-                            handleDnsConfigurationChange(usedNetworkType);
-                            if (VDBG) log("special network already active");
-                        } finally {
-                            Binder.restoreCallingIdentity(token);
+                    synchronized(this) {
+                        boolean addToList = true;
+                        if (restoreTimer < 0) {
+                            // In case there is no timer is specified for the feature,
+                            // make sure we don't add duplicate entry with the same request.
+                            for (FeatureUser u : mFeatureUsers) {
+                                if (u.isSameUser(f)) {
+                                    // Duplicate user is found. Do not add.
+                                    addToList = false;
+                                    break;
+                                }
+                            }
                         }
-                        return Phone.APN_ALREADY_ACTIVE;
+
+                        if (addToList) mFeatureUsers.add(f);
+                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
+                            // this gets used for per-pid dns when connected
+                            mNetRequestersPids[usedNetworkType].add(currentPid);
+                        }
                     }
-                    if (VDBG) log("special network already connecting");
+
+                    if (restoreTimer >= 0) {
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                                EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
+                    }
+
+                    if ((ni.isConnectedOrConnecting() == true) &&
+                            !network.isTeardownRequested()) {
+                        if (ni.isConnected() == true) {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                                // add the pid-specific dns
+                                handleDnsConfigurationChange(usedNetworkType);
+                                if (VDBG) log("special network already active");
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                            return Phone.APN_ALREADY_ACTIVE;
+                        }
+                        if (VDBG) log("special network already connecting");
+                        return Phone.APN_REQUEST_STARTED;
+                    }
+
+                    // check if the radio in play can make another contact
+                    // assume if cannot for now
+
+                    if (DBG) {
+                        log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
+                                feature);
+                    }
+                    network.reconnect();
                     return Phone.APN_REQUEST_STARTED;
-                }
-
-                // check if the radio in play can make another contact
-                // assume if cannot for now
-
-                if (DBG) {
-                    log("startUsingNetworkFeature reconnecting to " + networkType + ": " + feature);
-                }
-                network.reconnect();
-                return Phone.APN_REQUEST_STARTED;
-            } else {
-                // need to remember this unsupported request so we respond appropriately on stop
-                synchronized(this) {
-                    mFeatureUsers.add(f);
-                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
-                        // this gets used for per-pid dns when connected
-                        mNetRequestersPids[usedNetworkType].add(currentPid);
+                } else {
+                    // need to remember this unsupported request so we respond appropriately on stop
+                    synchronized(this) {
+                        mFeatureUsers.add(f);
+                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
+                            // this gets used for per-pid dns when connected
+                            mNetRequestersPids[usedNetworkType].add(currentPid);
+                        }
                     }
+                    return -1;
                 }
-                return -1;
             }
-        }
-        return Phone.APN_TYPE_NOT_AVAILABLE;
+            return Phone.APN_TYPE_NOT_AVAILABLE;
+         } finally {
+            if (DBG) {
+                final long execTime = SystemClock.elapsedRealtime() - startTime;
+                if (execTime > 250) {
+                    loge("startUsingNetworkFeature took too long: " + execTime + "ms");
+                } else {
+                    if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
+                }
+            }
+         }
     }
 
     // javadoc from interface
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a49ccf7..48219a4 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -139,6 +139,7 @@
 
     static final int MSG_UNBIND_METHOD = 3000;
     static final int MSG_BIND_METHOD = 3010;
+    static final int MSG_SET_ACTIVE = 3020;
 
     static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
 
@@ -195,6 +196,7 @@
     private PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
+    private final boolean mImeSelectedOnBoot;
 
     class SessionState {
         final ClientState client;
@@ -412,13 +414,9 @@
             }
 
             // Inform the current client of the change in active status
-            try {
-                if (mCurClient != null && mCurClient.client != null) {
-                    mCurClient.client.setActive(mScreenOn);
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
-                        + mCurClient.pid + " uid " + mCurClient.uid);
+            if (mCurClient != null && mCurClient.client != null) {
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, mCurClient));
             }
         }
     }
@@ -590,7 +588,6 @@
         mImeSwitcherNotification.vibrate = null;
         Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
         mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        mLastSystemLocale = mRes.getConfiguration().locale;
 
         mShowOngoingImeSwitcherForPhones = false;
 
@@ -612,11 +609,17 @@
         // mSettings should be created before buildInputMethodListLocked
         mSettings = new InputMethodSettings(
                 mRes, context.getContentResolver(), mMethodMap, mMethodList);
+
+        // Just checking if defaultImiId is empty or not
+        final String defaultImiId = Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+        mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
+
         buildInputMethodListLocked(mMethodList, mMethodMap);
         mSettings.enableAllIMEsIfThereIsNoEnabledIME();
 
-        if (TextUtils.isEmpty(Settings.Secure.getString(
-                mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD))) {
+        if (!mImeSelectedOnBoot) {
+            Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
             resetDefaultImeLocked(context);
         }
 
@@ -639,6 +642,10 @@
     }
 
     private void checkCurrentLocaleChangedLocked() {
+        if (!mSystemReady) {
+            // not system ready
+            return;
+        }
         final Locale newLocale = mRes.getConfiguration().locale;
         if (newLocale != null && !newLocale.equals(mLastSystemLocale)) {
             if (DEBUG) {
@@ -647,6 +654,7 @@
             buildInputMethodListLocked(mMethodList, mMethodMap);
             // Reset the current ime to the proper one
             resetDefaultImeLocked(mContext);
+            updateFromSettingsLocked();
             mLastSystemLocale = newLocale;
         }
     }
@@ -675,7 +683,10 @@
         }
     }
 
-    private static boolean isValidSystemDefaultIme(InputMethodInfo imi, Context context) {
+    private boolean isValidSystemDefaultIme(InputMethodInfo imi, Context context) {
+        if (!mSystemReady) {
+            return false;
+        }
         if (!isSystemIme(imi)) {
             return false;
         }
@@ -738,7 +749,6 @@
                         mContext.getSystemService(Context.KEYGUARD_SERVICE);
                 mNotificationManager = (NotificationManager)
                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-                mLastSystemLocale = mContext.getResources().getConfiguration().locale;
                 mStatusBar = statusBar;
                 statusBar.setIconVisibility("ime", false);
                 updateImeWindowStatusLocked();
@@ -748,6 +758,12 @@
                     mWindowManagerService.setOnHardKeyboardStatusChangeListener(
                             mHardKeyboardListener);
                 }
+                buildInputMethodListLocked(mMethodList, mMethodMap);
+                if (!mImeSelectedOnBoot) {
+                    Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
+                    checkCurrentLocaleChangedLocked();
+                }
+                mLastSystemLocale = mRes.getConfiguration().locale;
                 try {
                     startInputInnerLocked();
                 } catch (RuntimeException e) {
@@ -863,17 +879,12 @@
                             MSG_UNBIND_INPUT, mCurMethod));
                 }
             }
+
+            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                    MSG_SET_ACTIVE, 0, mCurClient));
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
                     MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
             mCurClient.sessionRequested = false;
-
-            // Call setActive(false) on the old client
-            try {
-                mCurClient.client.setActive(false);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
-                        + mCurClient.pid + " uid " + mCurClient.uid);
-            }
             mCurClient = null;
 
             hideInputMethodMenuLocked();
@@ -968,12 +979,8 @@
 
             // If the screen is on, inform the new client it is active
             if (mScreenOn) {
-                try {
-                    cs.client.setActive(mScreenOn);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Got RemoteException sending setActive notification to pid "
-                            + cs.pid + " uid " + cs.uid);
-                }
+                executeOrSendMessage(cs.client, mCaller.obtainMessageIO(
+                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, cs));
             }
         }
 
@@ -1421,34 +1428,41 @@
             throw new IllegalArgumentException("Unknown id: " + id);
         }
 
+        // See if we need to notify a subtype change within the same IME.
         if (id.equals(mCurMethodId)) {
-            InputMethodSubtype subtype = null;
-            if (subtypeId >= 0 && subtypeId < info.getSubtypeCount()) {
-                subtype = info.getSubtypeAt(subtypeId);
+            final int subtypeCount = info.getSubtypeCount();
+            if (subtypeCount <= 0) {
+                return;
             }
-            if (subtype != mCurrentSubtype) {
-                synchronized (mMethodMap) {
-                    if (subtype != null) {
-                        setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
-                    }
-                    if (mCurMethod != null) {
-                        try {
-                            refreshImeWindowVisibilityLocked();
-                            // If subtype is null, try to find the most applicable one from
-                            // getCurrentInputMethodSubtype.
-                            if (subtype == null) {
-                                subtype = getCurrentInputMethodSubtype();
-                            }
-                            mCurMethod.changeInputMethodSubtype(subtype);
-                        } catch (RemoteException e) {
-                            return;
-                        }
+            final InputMethodSubtype oldSubtype = mCurrentSubtype;
+            final InputMethodSubtype newSubtype;
+            if (subtypeId >= 0 && subtypeId < subtypeCount) {
+                newSubtype = info.getSubtypeAt(subtypeId);
+            } else {
+                // If subtype is null, try to find the most applicable one from
+                // getCurrentInputMethodSubtype.
+                newSubtype = getCurrentInputMethodSubtype();
+            }
+            if (newSubtype == null || oldSubtype == null) {
+                Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
+                        + ", new subtype = " + newSubtype);
+                return;
+            }
+            if (newSubtype != oldSubtype) {
+                setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
+                if (mCurMethod != null) {
+                    try {
+                        refreshImeWindowVisibilityLocked();
+                        mCurMethod.changeInputMethodSubtype(newSubtype);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Failed to call changeInputMethodSubtype");
                     }
                 }
             }
             return;
         }
 
+        // Changing to a different IME.
         final long ident = Binder.clearCallingIdentity();
         try {
             // Set a subtype to this input method.
@@ -1641,7 +1655,8 @@
                 }
 
                 if (mCurFocusedWindow == windowToken) {
-                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
+                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+                            + " attribute=" + attribute);
                     if (attribute != null) {
                         return startInputUncheckedLocked(cs, inputContext, attribute,
                                 controlFlags);
@@ -2113,6 +2128,15 @@
                     Slog.w(TAG, "Client died receiving input method " + args.arg2);
                 }
                 return true;
+            case MSG_SET_ACTIVE:
+                try {
+                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
+                            + ((ClientState)msg.obj).pid + " uid "
+                            + ((ClientState)msg.obj).uid);
+                }
+                return true;
 
             // --------------------------------------------------------------
             case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
@@ -2137,7 +2161,6 @@
         return subtypes;
     }
 
-
     private static ArrayList<InputMethodSubtype> getOverridingImplicitlyEnabledSubtypes(
             InputMethodInfo imi, String mode) {
         ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
@@ -2155,15 +2178,19 @@
         List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
         if (enabled != null && enabled.size() > 0) {
             // We'd prefer to fall back on a system IME, since that is safer.
-            int i=enabled.size();
+            int i = enabled.size();
+            int firstFoundSystemIme = -1;
             while (i > 0) {
                 i--;
                 final InputMethodInfo imi = enabled.get(i);
-                if (isSystemIme(imi) && !imi.isAuxiliaryIme()) {
-                    break;
+                if (isSystemImeThatHasEnglishSubtype(imi) && !imi.isAuxiliaryIme()) {
+                    return imi;
+                }
+                if (firstFoundSystemIme < 0 && isSystemIme(imi) && !imi.isAuxiliaryIme()) {
+                    firstFoundSystemIme = i;
                 }
             }
-            return enabled.get(i);
+            return enabled.get(Math.max(firstFoundSystemIme, 0));
         }
         return null;
     }
@@ -2238,11 +2265,17 @@
             }
         }
 
-        String defaultIme = Settings.Secure.getString(mContext
+        final String defaultImiId = Settings.Secure.getString(mContext
                 .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (!TextUtils.isEmpty(defaultIme) && !map.containsKey(defaultIme)) {
-            if (chooseNewDefaultIMELocked()) {
-                updateFromSettingsLocked();
+        if (!TextUtils.isEmpty(defaultImiId)) {
+            if (!map.containsKey(defaultImiId)) {
+                Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
+                if (chooseNewDefaultIMELocked()) {
+                    updateFromSettingsLocked();
+                }
+            } else {
+                // Double check that the default IME is certainly enabled.
+                setInputMethodEnabledLocked(defaultImiId, true);
             }
         }
     }
@@ -2626,7 +2659,8 @@
                 mCurrentSubtype = subtype;
             } else {
                 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
-                mCurrentSubtype = null;
+                // If the subtype is not specified, choose the most applicable one
+                mCurrentSubtype = getCurrentInputMethodSubtype();
             }
         }
 
@@ -3007,8 +3041,8 @@
             mContext = context;
             mPm = context.getPackageManager();
             mImms = imms;
-            mSystemLocaleStr =
-                    imms.mLastSystemLocale != null ? imms.mLastSystemLocale.toString() : "";
+            final Locale locale = context.getResources().getConfiguration().locale;
+            mSystemLocaleStr = locale != null ? locale.toString() : "";
         }
 
         private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 4582d67..1e707b2 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -105,6 +105,12 @@
     private static final String INSTALL_LOCATION_PROVIDER =
         android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
+    // Location Providers may sometimes deliver location updates
+    // slightly faster that requested - provide grace period so
+    // we don't unnecessarily filter events that are otherwise on
+    // time
+    private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100;
+
     // Set of providers that are explicitly enabled
     private final Set<String> mEnabledProviders = new HashSet<String>();
 
@@ -194,8 +200,9 @@
         final PendingIntent mPendingIntent;
         final Object mKey;
         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
+
         int mPendingBroadcasts;
-        String requiredPermissions;
+        String mRequiredPermissions;
 
         Receiver(ILocationListener listener) {
             mListener = listener;
@@ -286,7 +293,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -322,7 +329,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -362,7 +369,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -374,6 +381,7 @@
             return true;
         }
 
+        @Override
         public void binderDied() {
             if (LOCAL_LOGV) {
                 Slog.v(TAG, "Location listener died");
@@ -1026,7 +1034,7 @@
                     + Integer.toHexString(System.identityHashCode(this))
                     + " mProvider: " + mProvider + " mUid: " + mUid + "}";
         }
-        
+
         void dump(PrintWriter pw, String prefix) {
             pw.println(prefix + this);
             pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
@@ -1155,10 +1163,11 @@
 
         LocationProviderInterface p = mProvidersByName.get(provider);
         if (p == null) {
-            throw new IllegalArgumentException("provider=" + provider);
+            throw new IllegalArgumentException("requested provider " + provider +
+                    " doesn't exisit");
         }
-        receiver.requiredPermissions = checkPermissionsSafe(provider,
-                receiver.requiredPermissions);
+        receiver.mRequiredPermissions = checkPermissionsSafe(provider,
+                receiver.mRequiredPermissions);
 
         // so wakelock calls will succeed
         final int callingPid = Binder.getCallingPid();
@@ -1752,9 +1761,9 @@
             return true;
         }
 
-        // Don't broadcast same location again regardless of condition
-        // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
-        if (loc.getTime() == lastLoc.getTime()) {
+        // Check whether sufficient time has passed
+        long minTime = record.mMinTime;
+        if (loc.getTime() - lastLoc.getTime() < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
             return false;
         }
 
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d6606f6..1482d22 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -79,6 +79,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.Set;
 
 import javax.crypto.SecretKey;
@@ -178,7 +180,8 @@
     final private ArrayList<MountServiceBinderListener> mListeners =
             new ArrayList<MountServiceBinderListener>();
     private boolean                               mBooted = false;
-    private boolean                               mReady = false;
+    private CountDownLatch                        mConnectedSignal = new CountDownLatch(1);
+    private CountDownLatch                        mAsecsScanned = new CountDownLatch(1);
     private boolean                               mSendUmsConnectedOnBoot = false;
     // true if we should fake MEDIA_MOUNTED state for external storage
     private boolean                               mEmulateExternalStorage = false;
@@ -446,15 +449,30 @@
     final private HandlerThread mHandlerThread;
     final private Handler mHandler;
 
+    void waitForAsecScan() {
+        waitForLatch(mAsecsScanned);
+    }
+
     private void waitForReady() {
-        while (mReady == false) {
-            for (int retries = 5; retries > 0; retries--) {
-                if (mReady) {
+        waitForLatch(mConnectedSignal);
+    }
+
+    private void waitForLatch(CountDownLatch latch) {
+        if (latch == null) {
+            return;
+        }
+
+        for (;;) {
+            try {
+                if (latch.await(5000, TimeUnit.MILLISECONDS)) {
                     return;
+                } else {
+                    Slog.w(TAG, "Thread " + Thread.currentThread().getName()
+                            + " still waiting for MountService ready...");
                 }
-                SystemClock.sleep(1000);
+            } catch (InterruptedException e) {
+                Slog.w(TAG, "Interrupt while waiting for MountService to be ready.");
             }
-            Slog.w(TAG, "Waiting too long for mReady!");
         }
     }
 
@@ -627,7 +645,7 @@
          * Since we'll be calling back into the NativeDaemonConnector,
          * we need to do our work in a new thread.
          */
-        new Thread() {
+        new Thread("MountService#onDaemonConnected") {
             @Override
             public void run() {
                 /**
@@ -668,14 +686,19 @@
                     updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
                 }
 
-                // Let package manager load internal ASECs.
-                mPms.updateExternalMediaStatus(true, false);
-
                 /*
                  * Now that we've done our initialization, release
                  * the hounds!
                  */
-                mReady = true;
+                mConnectedSignal.countDown();
+                mConnectedSignal = null;
+
+                // Let package manager load internal ASECs.
+                mPms.scanAvailableAsecs();
+
+                // Notify people waiting for ASECs to be scanned that it's done.
+                mAsecsScanned.countDown();
+                mAsecsScanned = null;
             }
         }.start();
     }
@@ -1042,7 +1065,9 @@
     private static final String TAG_STORAGE_LIST = "StorageList";
     private static final String TAG_STORAGE = "storage";
 
-    private void readStorageList(Resources resources) {
+    private void readStorageList() {
+        Resources resources = mContext.getResources();
+
         int id = com.android.internal.R.xml.storage_list;
         XmlResourceParser parser = resources.getXml(id);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -1061,6 +1086,8 @@
 
                     CharSequence path = a.getText(
                             com.android.internal.R.styleable.Storage_mountPoint);
+                    int descriptionId = a.getResourceId(
+                            com.android.internal.R.styleable.Storage_storageDescription, -1);
                     CharSequence description = a.getText(
                             com.android.internal.R.styleable.Storage_storageDescription);
                     boolean primary = a.getBoolean(
@@ -1087,7 +1114,7 @@
                     } else {
                         String pathString = path.toString();
                         StorageVolume volume = new StorageVolume(pathString,
-                                description.toString(), removable, emulated,
+                                descriptionId, removable, emulated,
                                 mtpReserve, allowMassStorage, maxFileSize);
                         if (primary) {
                             if (mPrimaryVolume == null) {
@@ -1128,8 +1155,7 @@
      */
     public MountService(Context context) {
         mContext = context;
-        Resources resources = context.getResources();
-        readStorageList(resources);
+        readStorageList();
 
         if (mPrimaryVolume != null) {
             mExternalStoragePath = mPrimaryVolume.getPath();
@@ -1159,22 +1185,12 @@
         mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
 
         /*
-         * Vold does not run in the simulator, so pretend the connector thread
-         * ran and did its thing.
-         */
-        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
-            mReady = true;
-            mUmsEnabling = true;
-            return;
-        }
-
-        /*
          * Create the connection to vold with a maximum queue of twice the
          * amount of containers we'd ever expect to have. This keeps an
          * "asec list" from blocking a thread repeatedly.
          */
         mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
-        mReady = false;
+
         Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
 
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 6a6c585..f71125a 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -58,6 +58,7 @@
     private AtomicInteger mSequenceNumber;
 
     private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */
+    private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */
 
     /** Lock held whenever communicating with native daemon. */
     private final Object mDaemonLock = new Object();
@@ -299,6 +300,7 @@
         final int sequenceNumber = mSequenceNumber.incrementAndGet();
         final StringBuilder cmdBuilder =
                 new StringBuilder(Integer.toString(sequenceNumber)).append(' ');
+        final long startTime = SystemClock.elapsedRealtime();
 
         makeCommand(cmdBuilder, cmd, args);
 
@@ -327,9 +329,15 @@
                 loge("timed-out waiting for response to " + logCmd);
                 throw new NativeDaemonFailureException(logCmd, event);
             }
+            log("RMV <- {" + event + "}");
             events.add(event);
         } while (event.isClassContinue());
 
+        final long endTime = SystemClock.elapsedRealtime();
+        if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
+            loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
+        }
+
         if (event.isClassClientError()) {
             throw new NativeDaemonArgumentException(logCmd, event);
         }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 4536a6d..11644e3 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -166,7 +166,7 @@
         }
 
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 50);
+                new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);
         mThread = new Thread(mConnector, NETD_TAG);
 
         // Add ourself to the Watchdog monitors.
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2cc2704..38e08ae 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -178,6 +178,8 @@
     static final int ANIM_STEPS = 60; // nominal # of frames at 60Hz
     // Slower animation for autobrightness changes
     static final int AUTOBRIGHTNESS_ANIM_STEPS = 2 * ANIM_STEPS;
+    // Even slower animation for autodimness changes
+    static final int AUTODIMNESS_ANIM_STEPS = 15 * ANIM_STEPS;
     // Number of steps when performing a more immediate brightness change.
     static final int IMMEDIATE_ANIM_STEPS = 4;
 
@@ -1745,7 +1747,6 @@
                             + Integer.toHexString(mPowerState)
                             + " mSkippedScreenOn=" + mSkippedScreenOn);
                 }
-                mScreenBrightnessHandler.removeMessages(ScreenBrightnessAnimator.ANIMATE_LIGHTS);
                 mScreenBrightnessAnimator.animateTo(PowerManager.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0);
             }
         }
@@ -2159,6 +2160,8 @@
         static final int ANIMATE_POWER_OFF = 11;
         volatile int startValue;
         volatile int endValue;
+        volatile int startSensorValue;
+        volatile int endSensorValue;
         volatile int currentValue;
         private int currentMask;
         private int duration;
@@ -2182,7 +2185,7 @@
                         int value = msg.arg2;
                         long tStart = SystemClock.uptimeMillis();
                         if ((mask & SCREEN_BRIGHT_BIT) != 0) {
-                            if (mDebugLightAnimation) Log.v(TAG, "Set brightness: " + value);
+                            if (mDebugLightAnimation) Slog.v(TAG, "Set brightness: " + value);
                             mLcdLight.setBrightness(value, brightnessMode);
                         }
                         long elapsed = SystemClock.uptimeMillis() - tStart;
@@ -2194,12 +2197,12 @@
                         }
 
                         if (elapsed > 100) {
-                            Log.e(TAG, "Excessive delay setting brightness: " + elapsed
+                            Slog.e(TAG, "Excessive delay setting brightness: " + elapsed
                                     + "ms, mask=" + mask);
                         }
 
                         // Throttle brightness updates to frame refresh rate
-                        int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 0;
+                        int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 1;
                         synchronized(this) {
                             currentValue = value;
                         }
@@ -2227,25 +2230,41 @@
                         newValue = startValue + delta * elapsed / duration;
                         newValue = Math.max(PowerManager.BRIGHTNESS_OFF, newValue);
                         newValue = Math.min(PowerManager.BRIGHTNESS_ON, newValue);
+                        // Optimization to delay next step until a change will occur.
+                        if (delay > 0 && newValue == currentValue) {
+                            final int timePerStep = duration / Math.abs(delta);
+                            delay = Math.min(duration - elapsed, timePerStep);
+                            newValue += delta < 0 ? -1 : 1;
+                        }
+                        // adjust the peak sensor value until we get to the target sensor value
+                        delta = endSensorValue - startSensorValue;
+                        mHighestLightSensorValue = startSensorValue + delta * elapsed / duration;
                     } else {
                         newValue = endValue;
+                        mHighestLightSensorValue = endSensorValue;
                         mInitialAnimation = false;
                     }
 
                     if (mDebugLightAnimation) {
-                        Log.v(TAG, "Animating light: " + "start:" + startValue
+                        Slog.v(TAG, "Animating light: " + "start:" + startValue
                                 + ", end:" + endValue + ", elapsed:" + elapsed
                                 + ", duration:" + duration + ", current:" + currentValue
-                                + ", delay:" + delay);
+                                + ", newValue:" + newValue
+                                + ", delay:" + delay
+                                + ", highestSensor:" + mHighestLightSensorValue);
                     }
 
                     if (turningOff && !mHeadless && !mAnimateScreenLights) {
                         int mode = mScreenOffReason == OFF_BECAUSE_OF_PROX_SENSOR
                                 ? 0 : mAnimationSetting;
-                        if (mDebugLightAnimation) Log.v(TAG, "Doing power-off anim, mode=" + mode);
+                        if (mDebugLightAnimation) {
+                            Slog.v(TAG, "Doing power-off anim, mode=" + mode);
+                        }
                         mScreenBrightnessHandler.obtainMessage(ANIMATE_POWER_OFF, mode, 0)
                                 .sendToTarget();
                     }
+                    mScreenBrightnessHandler.removeMessages(
+                            ScreenBrightnessAnimator.ANIMATE_LIGHTS);
                     Message msg = mScreenBrightnessHandler
                             .obtainMessage(ANIMATE_LIGHTS, mask, newValue);
                     mScreenBrightnessHandler.sendMessageDelayed(msg, delay);
@@ -2259,16 +2278,24 @@
         }
 
         public void animateTo(int target, int mask, int animationDuration) {
+            animateTo(target, mHighestLightSensorValue, mask, animationDuration);
+        }
+
+        public void animateTo(int target, int sensorTarget, int mask, int animationDuration) {
             synchronized(this) {
                 startValue = currentValue;
                 endValue = target;
+                startSensorValue = mHighestLightSensorValue;
+                endSensorValue = sensorTarget;
                 currentMask = mask;
                 duration = (int) (mWindowScaleAnimation * animationDuration);
                 startTimeMillis = SystemClock.elapsedRealtime();
                 mInitialAnimation = currentValue == 0 && target > 0;
 
                 if (mDebugLightAnimation) {
-                    Log.v(TAG, "animateTo(target=" + target + ", mask=" + mask
+                    Slog.v(TAG, "animateTo(target=" + target
+                            + ", sensor=" + sensorTarget
+                            + ", mask=" + mask
                             + ", duration=" + animationDuration +")"
                             + ", currentValue=" + currentValue
                             + ", startTime=" + startTimeMillis);
@@ -2612,9 +2639,11 @@
             return;
         }
 
-        // do not allow light sensor value to decrease
-        if (mHighestLightSensorValue < value) {
-            mHighestLightSensorValue = value;
+        final int stepsToTargetLevel;
+        if (mHighestLightSensorValue <= value) {
+            stepsToTargetLevel = AUTOBRIGHTNESS_ANIM_STEPS;
+        } else {
+            stepsToTargetLevel = AUTODIMNESS_ANIM_STEPS;
         }
 
         if (mLightSensorValue != value) {
@@ -2623,9 +2652,7 @@
                 // use maximum light sensor value seen since screen went on for LCD to avoid flicker
                 // we only do this if we are undocked, since lighting should be stable when
                 // stationary in a dock.
-                int lcdValue = getAutoBrightnessValue(
-                        (mIsDocked ? value : mHighestLightSensorValue),
-                        mLcdBacklightValues);
+                int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
                 int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
                 int keyboardValue;
                 if (mKeyboardVisible) {
@@ -2645,9 +2672,8 @@
 
                 if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
                     if (!mSkippedScreenOn && !mInitialAnimation) {
-                        int steps = immediate ? IMMEDIATE_ANIM_STEPS : AUTOBRIGHTNESS_ANIM_STEPS;
-                        mScreenBrightnessAnimator.cancelAnimation();
-                        mScreenBrightnessAnimator.animateTo(lcdValue,
+                        int steps = immediate ? IMMEDIATE_ANIM_STEPS : stepsToTargetLevel;
+                        mScreenBrightnessAnimator.animateTo(lcdValue, value,
                                 SCREEN_BRIGHT_BIT, steps * NOMINAL_FRAME_TIME_MS);
                     }
                 }
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 8429086..78c0c12 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -489,7 +489,8 @@
         synchronized (mNotifications) {
             final StatusBarNotification n = mNotifications.remove(key);
             if (n == null) {
-                throw new IllegalArgumentException("removeNotification key not found: " + key);
+                Slog.e(TAG, "removeNotification key not found: " + key);
+                return;
             }
             if (mBar != null) {
                 try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bb103580..eaecd4c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -320,6 +320,21 @@
         }
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            MountService mountService = null;
+            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+                try {
+                    /*
+                     * NotificationManagerService is dependant on MountService,
+                     * (for media / usb notifications) so we must start MountService first.
+                     */
+                    Slog.i(TAG, "Mount Service");
+                    mountService = new MountService(context);
+                    ServiceManager.addService("mount", mountService);
+                } catch (Throwable e) {
+                    reportWtf("starting Mount Service", e);
+                }
+            }
+
             try {
                 Slog.i(TAG,  "LockSettingsService");
                 lockSettings = new LockSettingsService(context);
@@ -441,17 +456,13 @@
                 reportWtf("starting UpdateLockService", e);
             }
 
-            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
-                try {
-                    /*
-                     * NotificationManagerService is dependant on MountService,
-                     * (for media / usb notifications) so we must start MountService first.
-                     */
-                    Slog.i(TAG, "Mount Service");
-                    ServiceManager.addService("mount", new MountService(context));
-                } catch (Throwable e) {
-                    reportWtf("starting Mount Service", e);
-                }
+            /*
+             * MountService has a few dependencies: Notification Manager and
+             * AppWidget Provider. Make sure MountService is completely started
+             * first before continuing.
+             */
+            if (mountService != null) {
+                mountService.waitForAsecScan();
             }
 
             try {
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 499ff7a..c7b336f 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -254,10 +254,8 @@
                         return scs;
                     } else if (candidate == null) {
                         final String scsLocale = scs.getLocale();
-                        if (candidateLocale.length() >= 2
-                                && scsLocale.length() >= 2
-                                && candidateLocale.substring(0, 2).equals(
-                                        scsLocale.substring(0, 2))) {
+                        if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
+                                && candidateLocale.startsWith(scsLocale)) {
                             // Fall back to the applicable language
                             candidate = scs;
                         }
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 84daead..c936ef9 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -93,6 +93,7 @@
     private final int mDefaultUiModeType;
     private final boolean mCarModeKeepsScreenOn;
     private final boolean mDeskModeKeepsScreenOn;
+    private final boolean mTelevision;
 
     private boolean mComputedNightMode;
     private int mCurUiMode = 0;
@@ -354,7 +355,9 @@
                 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
         mDeskModeKeepsScreenOn = (context.getResources().getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
-        
+        mTelevision = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_TELEVISION);
+
         mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
     }
@@ -455,7 +458,8 @@
     }
 
     final void updateConfigurationLocked(boolean sendIt) {
-        int uiMode = mDefaultUiModeType;
+        int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION
+                : mDefaultUiModeType;
         if (mCarModeEnabled) {
             uiMode = Configuration.UI_MODE_TYPE_CAR;
         } else if (isDeskDockState(mDockState)) {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index bb38cd9..1f03d17 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -376,11 +376,7 @@
                     @Override
                     public void onReceive(Context context, Intent intent) {
                         mAirplaneModeOn.set(isAirplaneModeOn());
-                        /* On airplane mode disable, restore wifi state if necessary */
-                        if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
-                            mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
-                                persistWifiState(true);
-                        }
+                        handleAirplaneModeToggled(mAirplaneModeOn.get());
                         updateWifiState();
                     }
                 },
@@ -447,7 +443,10 @@
         boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
-        setWifiEnabled(wifiEnabled);
+
+        // If we are already disabled (could be due to airplane mode), avoid changing persist
+        // state here
+        if (wifiEnabled) setWifiEnabled(wifiEnabled);
 
         mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
                makeWifiWatchdogStateMachine(mContext);
@@ -485,26 +484,43 @@
         }
     }
 
-    private void persistWifiState(boolean enabled) {
-        final ContentResolver cr = mContext.getContentResolver();
-        boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
-        if (enabled) {
-            if (airplane) {
-                mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+    private void handleWifiToggled(boolean wifiEnabled) {
+        boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable();
+        if (wifiEnabled) {
+            if (airplaneEnabled) {
+                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
             } else {
-                mPersistWifiState.set(WIFI_ENABLED);
+                persistWifiState(WIFI_ENABLED);
             }
         } else {
-            if (airplane) {
-                mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
-            } else {
-                mPersistWifiState.set(WIFI_DISABLED);
-            }
+            // When wifi state is disabled, we do not care
+            // if airplane mode is on or not. The scenario of
+            // wifi being disabled due to airplane mode being turned on
+            // is handled handleAirplaneModeToggled()
+            persistWifiState(WIFI_DISABLED);
         }
-
-        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
     }
 
+    private void handleAirplaneModeToggled(boolean airplaneEnabled) {
+        if (airplaneEnabled) {
+            // Wifi disabled due to airplane on
+            if (mWifiEnabled) {
+                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
+            }
+        } else {
+            /* On airplane mode disable, restore wifi state if necessary */
+            if (testAndClearWifiSavedState() ||
+                    mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
+                persistWifiState(WIFI_ENABLED);
+            }
+        }
+    }
+
+    private void persistWifiState(int state) {
+        final ContentResolver cr = mContext.getContentResolver();
+        mPersistWifiState.set(state);
+        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, state);
+    }
 
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
@@ -562,6 +578,8 @@
      */
     public synchronized boolean setWifiEnabled(boolean enable) {
         enforceChangePermission();
+        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
         if (DBG) {
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
@@ -576,12 +594,9 @@
          * only CHANGE_WIFI_STATE is enforced
          */
 
-        /* Avoids overriding of airplane state when wifi is already in the expected state */
-        if (enable != mWifiEnabled) {
-            long ident = Binder.clearCallingIdentity();
-            persistWifiState(enable);
-            Binder.restoreCallingIdentity(ident);
-        }
+        long ident = Binder.clearCallingIdentity();
+        handleWifiToggled(enable);
+        Binder.restoreCallingIdentity(ident);
 
         if (enable) {
             if (!mIsReceiverRegistered) {
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 3fbac38..3e35b20d 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -16,7 +16,6 @@
 
 package com.android.server.accessibility;
 
-import com.android.server.accessibility.TouchExplorer.GestureListener;
 import com.android.server.input.InputFilter;
 
 import android.content.Context;
@@ -40,7 +39,7 @@
 
     private final PowerManager mPm;
 
-    private final GestureListener mGestureListener;
+    private final AccessibilityManagerService mAms;
 
     /**
      * This is an interface for explorers that take a {@link MotionEvent}
@@ -73,10 +72,10 @@
 
     private int mTouchscreenSourceDeviceId;
 
-    public AccessibilityInputFilter(Context context, GestureListener gestureListener) {
+    public AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
         super(context.getMainLooper());
         mContext = context;
-        mGestureListener = gestureListener;
+        mAms = service;
         mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
     }
 
@@ -85,7 +84,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter installed.");
         }
-        mTouchExplorer = new TouchExplorer(this, mContext, mGestureListener);
+        mTouchExplorer = new TouchExplorer(this, mContext, mAms);
         super.onInstalled();
     }
 
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1937bad..039efbd 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -24,17 +24,21 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
@@ -57,7 +61,9 @@
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -65,8 +71,8 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
+import com.android.internal.R;
 import com.android.internal.content.PackageMonitor;
-import com.android.server.accessibility.TouchExplorer.GestureListener;
 import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -89,8 +95,7 @@
  *
  * @hide
  */
-public class AccessibilityManagerService extends IAccessibilityManager.Stub
-        implements GestureListener {
+public class AccessibilityManagerService extends IAccessibilityManager.Stub {
 
     private static final boolean DEBUG = false;
 
@@ -101,6 +106,8 @@
 
     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
 
+    private static final int MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG = 1;
+
     private static int sIdCounter = 0;
 
     private static int sNextWindowId;
@@ -127,6 +134,8 @@
 
     private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':');
 
+    private final Rect mTempRect = new Rect();
+
     private PackageManager mPackageManager;
 
     private int mHandledFeedbackTypes = 0;
@@ -145,23 +154,15 @@
 
     private final SecurityPolicy mSecurityPolicy;
 
+    private final MainHanler mMainHandler;
+
     private Service mUiAutomationService;
 
-    /**
-     * Handler for delayed event dispatch.
-     */
-    private Handler mHandler = new Handler() {
+    private Service mQueryBridge;
 
-        @Override
-        public void handleMessage(Message message) {
-            Service service = (Service) message.obj;
-            int eventType = message.arg1;
+    private boolean mTouchExplorationGestureEnded;
 
-            synchronized (mLock) {
-                notifyAccessibilityEventLocked(service, eventType);
-            }
-        }
-    };
+    private boolean mTouchExplorationGestureStarted;
 
     /**
      * Creates a new instance.
@@ -174,7 +175,7 @@
         mWindowManagerService = (WindowManagerService) ServiceManager.getService(
                 Context.WINDOW_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
-
+        mMainHandler = new MainHanler();
         registerPackageChangeAndBootCompletedBroadcastReceiver();
         registerSettingsContentObservers();
     }
@@ -190,8 +191,11 @@
             @Override
             public void onSomePackagesChanged() {
                 synchronized (mLock) {
-                    populateAccessibilityServiceListLocked();
-                    manageServicesLocked();
+                    // We will update when the automation service dies.
+                    if (mUiAutomationService == null) {
+                        populateAccessibilityServiceListLocked();
+                        manageServicesLocked();
+                    }
                 }
             }
 
@@ -241,11 +245,14 @@
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
                     synchronized (mLock) {
-                        populateAccessibilityServiceListLocked();
-                        handleAccessibilityEnabledSettingChangedLocked();
-                        handleTouchExplorationEnabledSettingChangedLocked();
-                        updateInputFilterLocked();
-                        sendStateToClientsLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            populateAccessibilityServiceListLocked();
+                            handleAccessibilityEnabledSettingChangedLocked();
+                            handleTouchExplorationEnabledSettingChangedLocked();
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
+                        }
                     }
 
                     return;
@@ -293,9 +300,12 @@
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
                     synchronized (mLock) {
-                        handleAccessibilityEnabledSettingChangedLocked();
-                        updateInputFilterLocked();
-                        sendStateToClientsLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            handleAccessibilityEnabledSettingChangedLocked();
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
+                        }
                     }
                 }
             });
@@ -308,9 +318,12 @@
                     public void onChange(boolean selfChange) {
                         super.onChange(selfChange);
                         synchronized (mLock) {
-                            handleTouchExplorationEnabledSettingChangedLocked();
-                            updateInputFilterLocked();
-                            sendStateToClientsLocked();
+                            // We will update when the automation service dies.
+                            if (mUiAutomationService == null) {
+                                handleTouchExplorationEnabledSettingChangedLocked();
+                                updateInputFilterLocked();
+                                sendStateToClientsLocked();
+                            }
                         }
                     }
                 });
@@ -323,7 +336,10 @@
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
                     synchronized (mLock) {
-                        manageServicesLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            manageServicesLocked();
+                        }
                     }
                 }
             });
@@ -348,15 +364,37 @@
     }
 
     public boolean sendAccessibilityEvent(AccessibilityEvent event) {
+        // The event for gesture start should be strictly before the
+        // first hover enter event for the gesture.
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+                && mTouchExplorationGestureStarted) {
+            mTouchExplorationGestureStarted = false;
+            AccessibilityEvent gestureStartEvent = AccessibilityEvent.obtain(
+                    AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+            sendAccessibilityEvent(gestureStartEvent);
+        }
+
         synchronized (mLock) {
             if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
-                mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
+                mSecurityPolicy.updateActiveWindowAndEventSourceLocked(event);
                 notifyAccessibilityServicesDelayedLocked(event, false);
                 notifyAccessibilityServicesDelayedLocked(event, true);
             }
         }
+
+        // The event for gesture end should be strictly after the
+        // last hover exit event for the gesture.
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
+                && mTouchExplorationGestureEnded) {
+            mTouchExplorationGestureEnded = false;
+            AccessibilityEvent gestureEndEvent = AccessibilityEvent.obtain(
+                    AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
+            sendAccessibilityEvent(gestureEndEvent);
+        }
+
         event.recycle();
         mHandledFeedbackTypes = 0;
+
         return (OWN_PROCESS_ID != Binder.getCallingPid());
     }
 
@@ -471,8 +509,7 @@
         }
     }
 
-    @Override
-    public boolean onGesture(int gestureId) {
+    boolean onGesture(int gestureId) {
         synchronized (mLock) {
             boolean handled = notifyGestureLocked(gestureId, false);
             if (!handled) {
@@ -482,6 +519,65 @@
         }
     }
 
+    /**
+     * Gets the bounds of the accessibility focus if the provided,
+     * point coordinates are within the currently active window
+     * and accessibility focus is found within the latter.
+     *
+     * @param x X coordinate.
+     * @param y Y coordinate
+     * @param outBounds The output to which to write the focus bounds.
+     * @return The accessibility focus rectangle if the point is in the
+     *     window and the window has accessibility focus.
+     */
+    boolean getAccessibilityFocusBounds(int x, int y, Rect outBounds) {
+        // Instead of keeping track of accessibility focus events per
+        // window to be able to find the focus in the active window,
+        // we take a stateless approach and look it up. This is fine
+        // since we do this only when the user clicks/long presses.
+        Service service = getQueryBridge();
+        final int connectionId = service.mId;
+        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+        client.addConnection(connectionId, service);
+        try {
+            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
+                    .getRootInActiveWindow(connectionId);
+            if (root == null) {
+                return false;
+            }
+            Rect bounds = mTempRect;
+            root.getBoundsInScreen(bounds);
+            if (!bounds.contains(x, y)) {
+                return false;
+            }
+            AccessibilityNodeInfo focus = root.findFocus(
+                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+            if (focus == null) {
+                return false;
+            }
+            focus.getBoundsInScreen(outBounds);
+            return true;
+        } finally {
+            client.removeConnection(connectionId);
+        }
+    }
+
+    private Service getQueryBridge() {
+        if (mQueryBridge == null) {
+            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+            mQueryBridge = new Service(null, info, true);
+        }
+        return mQueryBridge;
+    }
+
+    public void touchExplorationGestureEnded() {
+        mTouchExplorationGestureEnded = true;
+    }
+
+    public void touchExplorationGestureStarted() {
+        mTouchExplorationGestureStarted = true;
+    }
+
     private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
         // TODO: Now we are giving the gestures to the last enabled
         //       service that can handle them which is the last one
@@ -495,12 +591,7 @@
         for (int i = mServices.size() - 1; i >= 0; i--) {
             Service service = mServices.get(i);
             if (service.mReqeustTouchExplorationMode && service.mIsDefault == isDefault) {
-                try {
-                    service.mServiceInterface.onGesture(gestureId);
-                } catch (RemoteException re) {
-                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
-                            + " to " + service.mService, re);
-                }
+                service.notifyGesture(gestureId);
                 return true;
             }
         }
@@ -532,6 +623,18 @@
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
             ResolveInfo resolveInfo = installedServices.get(i);
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            // For now we are enforcing this if the target version is JellyBean or
+            // higher and in a later release we will enforce this for everyone.
+            if (serviceInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN
+                    && !android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
+                    serviceInfo.permission)) {
+                Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
+                        serviceInfo.packageName, serviceInfo.name).flattenToShortString()
+                        + ": it does not require the permission "
+                        + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
+                continue;
+            }
             AccessibilityServiceInfo accessibilityServiceInfo;
             try {
                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
@@ -560,7 +663,7 @@
                 if (service.mIsDefault == isDefault) {
                     if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) {
                         mHandledFeedbackTypes |= service.mFeedbackType;
-                        notifyAccessibilityServiceDelayedLocked(service, event);
+                        service.notifyAccessibilityEvent(event);
                     }
                 }
             }
@@ -573,90 +676,6 @@
     }
 
     /**
-     * Performs an {@link AccessibilityService} delayed notification. The delay is configurable
-     * and denotes the period after the last event before notifying the service.
-     *
-     * @param service The service.
-     * @param event The event.
-     */
-    private void notifyAccessibilityServiceDelayedLocked(Service service,
-            AccessibilityEvent event) {
-        synchronized (mLock) {
-            final int eventType = event.getEventType();
-            // Make a copy since during dispatch it is possible the event to
-            // be modified to remove its source if the receiving service does
-            // not have permission to access the window content.
-            AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
-            AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
-            service.mPendingEvents.put(eventType, newEvent);
-
-            final int what = eventType | (service.mId << 16);
-            if (oldEvent != null) {
-                mHandler.removeMessages(what);
-                oldEvent.recycle();
-            }
-
-            Message message = mHandler.obtainMessage(what, service);
-            message.arg1 = eventType;
-            mHandler.sendMessageDelayed(message, service.mNotificationTimeout);
-        }
-    }
-
-    /**
-     * Notifies an accessibility service client for a scheduled event given the event type.
-     *
-     * @param service The service client.
-     * @param eventType The type of the event to dispatch.
-     */
-    private void notifyAccessibilityEventLocked(Service service, int eventType) {
-        IAccessibilityServiceClient listener = service.mServiceInterface;
-
-        // If the service died/was disabled while the message for dispatching
-        // the accessibility event was propagating the listener may be null.
-        if (listener == null) {
-            return;
-        }
-
-        AccessibilityEvent event = service.mPendingEvents.get(eventType);
-
-        // Check for null here because there is a concurrent scenario in which this
-        // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
-        // which posts a message for dispatching an event. 2) The message is pulled
-        // from the queue by the handler on the service thread and the latter is
-        // just about to acquire the lock and call this method. 3) Now another binder
-        // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
-        // so the service thread waits for the lock; 4) The binder thread replaces
-        // the event with a more recent one (assume the same event type) and posts a
-        // dispatch request releasing the lock. 5) Now the main thread is unblocked and
-        // dispatches the event which is removed from the pending ones. 6) And ... now
-        // the service thread handles the last message posted by the last binder call
-        // but the event is already dispatched and hence looking it up in the pending
-        // ones yields null. This check is much simpler that keeping count for each
-        // event type of each service to catch such a scenario since only one message
-        // is processed at a time.
-        if (event == null) {
-            return;
-        }
-
-        service.mPendingEvents.remove(eventType);
-        try {
-            if (mSecurityPolicy.canRetrieveWindowContent(service)) {
-                event.setConnectionId(service.mId);
-            } else {
-                event.setSource(null);
-            }
-            event.setSealed(true);
-            listener.onAccessibilityEvent(event);
-            event.recycle();
-            if (DEBUG) {
-                Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
-            }
-        } catch (RemoteException re) {
-            Slog.e(LOG_TAG, "Error during sending " + event + " to " + service.mService, re);
-        }
-    }
-
-    /**
      * Adds a service.
      *
      * @param service The service to add.
@@ -670,6 +689,7 @@
             mServices.add(service);
             mComponentNameToServiceMap.put(service.mComponentName, service);
             updateInputFilterLocked();
+            tryEnableTouchExploration(service);
         } catch (RemoteException e) {
             /* do nothing */
         }
@@ -687,10 +707,10 @@
             return false;
         }
         mComponentNameToServiceMap.remove(service.mComponentName);
-        mHandler.removeMessages(service.mId);
         service.unlinkToOwnDeath();
         service.dispose();
         updateInputFilterLocked();
+        tryDisableTouchExploration(service);
         return removed;
     }
 
@@ -742,10 +762,6 @@
      * Manages services by starting enabled ones and stopping disabled ones.
      */
     private void manageServicesLocked() {
-        // While the UI automation service is running it takes over.
-        if (mUiAutomationService != null) {
-            return;
-        }
         populateEnabledServicesLocked(mEnabledServices);
         final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
                 mEnabledServices);
@@ -919,6 +935,34 @@
                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
     }
 
+    private void tryEnableTouchExploration(final Service service) {
+        if (!mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
+            if (!service.mIsAutomation) {
+                mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG,
+                        service).sendToTarget();
+            } else {
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1);
+            }
+        }
+    }
+
+    private void tryDisableTouchExploration(Service service) {
+        if (mIsTouchExplorationEnabled && service.mReqeustTouchExplorationMode) {
+            synchronized (mLock) {
+                final int serviceCount = mServices.size();
+                for (int i = 0; i < serviceCount; i++) {
+                    Service other = mServices.get(i);
+                    if (other != service && other.mRequestTouchExplorationMode) {
+                        return;
+                    }
+                }
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0);
+            }
+        }
+    }
+
     private class AccessibilityConnectionWrapper implements DeathRecipient {
         private final int mWindowId;
         private final IAccessibilityInteractionConnection mConnection;
@@ -946,6 +990,42 @@
         }
     }
 
+    private class MainHanler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            final int type = msg.what;
+            switch (type) {
+                case MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG: {
+                    Service service = (Service) msg.obj;
+                    String label = service.mResolveInfo.loadLabel(
+                            mContext.getPackageManager()).toString();
+                    final AlertDialog dialog = new AlertDialog.Builder(mContext)
+                        .setIcon(android.R.drawable.ic_dialog_alert)
+                        .setPositiveButton(android.R.string.ok, new OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                Settings.Secure.putInt(mContext.getContentResolver(),
+                                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1);
+                            }
+                        })
+                        .setNegativeButton(android.R.string.cancel, new OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                dialog.dismiss();
+                            }
+                        })
+                        .setTitle(R.string.enable_explore_by_touch_warning_title)
+                        .setMessage(mContext.getString(
+                            R.string.enable_explore_by_touch_warning_message, label))
+                        .create();
+                    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+                    dialog.setCanceledOnTouchOutside(true);
+                    dialog.show();
+                }
+            }
+        }
+    }
+
     /**
      * This class represents an accessibility service. It stores all per service
      * data required for the service management, provides API for starting/stopping the
@@ -956,6 +1036,11 @@
      */
     class Service extends IAccessibilityServiceConnection.Stub
             implements ServiceConnection, DeathRecipient {
+
+        // We pick the MSB to avoid collision since accessibility event types are
+        // used as message types allowing us to remove messages per event type. 
+        private static final int MSG_ON_GESTURE = 0x80000000;
+
         int mId = 0;
 
         AccessibilityServiceInfo mAccessibilityServiceInfo;
@@ -972,6 +1057,8 @@
 
         boolean mIsDefault;
 
+        boolean mRequestTouchExplorationMode;
+
         boolean mIncludeNotImportantViews;
 
         long mNotificationTimeout;
@@ -988,12 +1075,35 @@
 
         final Rect mTempBounds = new Rect();
 
+        final ResolveInfo mResolveInfo;
+
         // the events pending events to be dispatched to this service
         final SparseArray<AccessibilityEvent> mPendingEvents =
             new SparseArray<AccessibilityEvent>();
 
+        /**
+         * Handler for delayed event dispatch.
+         */
+        public Handler mHandler = new Handler(mMainHandler.getLooper()) {
+            @Override
+            public void handleMessage(Message message) {
+                final int type = message.what;
+                switch (type) {
+                    case MSG_ON_GESTURE: {
+                        final int gestureId = message.arg1;
+                        notifyGestureInternal(gestureId);
+                    } break;
+                    default: {
+                        final int eventType = type;
+                        notifyAccessibilityEventInternal(eventType);
+                    } break;
+                }
+            }
+        };
+
         public Service(ComponentName componentName,
                 AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
+            mResolveInfo = accessibilityServiceInfo.getResolveInfo();
             mId = sIdCounter++;
             mComponentName = componentName;
             mAccessibilityServiceInfo = accessibilityServiceInfo;
@@ -1030,6 +1140,9 @@
                     (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
             }
 
+            mRequestTouchExplorationMode = (info.flags
+                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+
             synchronized (mLock) {
                 tryAddServiceLocked(this);
             }
@@ -1315,11 +1428,11 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+            final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                final int flags = (mIncludeNotImportantViews) ?
-                        AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
-                final int interrogatingPid = Binder.getCallingPid();
                 connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
                         interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
@@ -1382,10 +1495,117 @@
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
                     mUiAutomationService = null;
+
                     handleAccessibilityEnabledSettingChangedLocked();
+                    sendStateToClientsLocked();
+
                     handleTouchExplorationEnabledSettingChangedLocked();
                     updateInputFilterLocked();
-                    sendStateToClientsLocked();
+
+                    populateAccessibilityServiceListLocked();
+                    manageServicesLocked();
+                }
+            }
+        }
+
+        /**
+         * Performs a notification for an {@link AccessibilityEvent}.
+         *
+         * @param event The event.
+         */
+        public void notifyAccessibilityEvent(AccessibilityEvent event) {
+            synchronized (mLock) {
+                final int eventType = event.getEventType();
+                // Make a copy since during dispatch it is possible the event to
+                // be modified to remove its source if the receiving service does
+                // not have permission to access the window content.
+                AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
+                AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
+                mPendingEvents.put(eventType, newEvent);
+
+                final int what = eventType;
+                if (oldEvent != null) {
+                    mHandler.removeMessages(what);
+                    oldEvent.recycle();
+                }
+
+                Message message = mHandler.obtainMessage(what);
+                mHandler.sendMessageDelayed(message, mNotificationTimeout);
+            }
+        }
+
+        /**
+         * Notifies an accessibility service client for a scheduled event given the event type.
+         *
+         * @param eventType The type of the event to dispatch.
+         */
+        private void notifyAccessibilityEventInternal(int eventType) {
+            IAccessibilityServiceClient listener;
+            AccessibilityEvent event;
+
+            synchronized (mLock) {
+                listener = mServiceInterface;
+
+                // If the service died/was disabled while the message for dispatching
+                // the accessibility event was propagating the listener may be null.
+                if (listener == null) {
+                    return;
+                }
+
+                event = mPendingEvents.get(eventType);
+
+                // Check for null here because there is a concurrent scenario in which this
+                // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
+                // which posts a message for dispatching an event. 2) The message is pulled
+                // from the queue by the handler on the service thread and the latter is
+                // just about to acquire the lock and call this method. 3) Now another binder
+                // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
+                // so the service thread waits for the lock; 4) The binder thread replaces
+                // the event with a more recent one (assume the same event type) and posts a
+                // dispatch request releasing the lock. 5) Now the main thread is unblocked and
+                // dispatches the event which is removed from the pending ones. 6) And ... now
+                // the service thread handles the last message posted by the last binder call
+                // but the event is already dispatched and hence looking it up in the pending
+                // ones yields null. This check is much simpler that keeping count for each
+                // event type of each service to catch such a scenario since only one message
+                // is processed at a time.
+                if (event == null) {
+                    return;
+                }
+
+                mPendingEvents.remove(eventType);
+                if (mSecurityPolicy.canRetrieveWindowContent(this)) {
+                    event.setConnectionId(mId);
+                } else {
+                    event.setSource(null);
+                }
+                event.setSealed(true);
+            }
+
+            try {
+                listener.onAccessibilityEvent(event);
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
+                }
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
+            } finally {
+                event.recycle();
+            }
+        }
+
+        public void notifyGesture(int gestureId) {
+            mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
+        }
+
+        private void notifyGestureInternal(int gestureId) {
+            IAccessibilityServiceClient listener = mServiceInterface;
+            if (listener != null) {
+                try {
+                    listener.onGesture(gestureId);
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
+                            + " to " + mService, re);
                 }
             }
         }
@@ -1441,7 +1661,7 @@
 
         private int resolveAccessibilityWindowId(int accessibilityWindowId) {
             if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
-                return mSecurityPolicy.mRetrievalAlowingWindowId;
+                return mSecurityPolicy.mActiveWindowId;
             }
             return accessibilityWindowId;
         }
@@ -1484,24 +1704,35 @@
             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
 
-        private static final int RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES =
-            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
-            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
-
-        private int mRetrievalAlowingWindowId;
+        private int mActiveWindowId;
 
         private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
             // Send window changed event only for the retrieval allowing window.
             return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
-                    || event.getWindowId() == mRetrievalAlowingWindowId);
+                    || event.getWindowId() == mActiveWindowId);
         }
 
-        public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) {
+        public void updateActiveWindowAndEventSourceLocked(AccessibilityEvent event) {
+            // The active window is either the window that has input focus or
+            // the window that the user is currently touching. If the user is
+            // touching a window that does not have input focus as soon as the
+            // the user stops touching that window the focused window becomes
+            // the active one.
             final int windowId = event.getWindowId();
             final int eventType = event.getEventType();
-            if ((eventType & RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES) != 0) {
-                mRetrievalAlowingWindowId = windowId;
+            switch (eventType) {
+                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
+                    if (getFocusedWindowId() == windowId) {
+                        mActiveWindowId = windowId;
+                    }
+                } break;
+                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
+                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+                    mActiveWindowId = windowId;
+                } break;
+                case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
+                    mActiveWindowId = getFocusedWindowId();
+                } break;
             }
             if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
                 event.setSource(null);
@@ -1509,7 +1740,7 @@
         }
 
         public int getRetrievalAllowingWindowLocked() {
-            return mRetrievalAlowingWindowId;
+            return mActiveWindowId;
         }
 
         public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
@@ -1537,7 +1768,7 @@
         }
 
         private boolean isRetrievalAllowingWindow(int windowId) {
-            return (mRetrievalAlowingWindowId == windowId);
+            return (mActiveWindowId == windowId);
         }
 
         private boolean isActionPermitted(int action) {
@@ -1554,5 +1785,22 @@
                         + " required to call " + function);
             }
         }
+
+        private int getFocusedWindowId() {
+            // We call this only on window focus change or after touch
+            // exploration gesture end and the shown windows are not that
+            // many, so the linear look up is just fine.
+            IBinder token = mWindowManagerService.getFocusedWindowClientToken();
+            if (token != null) {
+                SparseArray<IBinder> windows = mWindowIdToWindowTokenMap;
+                final int windowCount = windows.size();
+                for (int i = 0; i < windowCount; i++) {
+                    if (windows.valueAt(i) == token) {
+                        return windows.keyAt(i);
+                    }
+                }
+            }
+            return -1;
+        }
     }
 }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 39012e6..b0b2b8d 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -16,9 +16,6 @@
 
 package com.android.server.accessibility;
 
-import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END;
-import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
-
 import android.content.Context;
 import android.gesture.Gesture;
 import android.gesture.GestureLibraries;
@@ -26,17 +23,19 @@
 import android.gesture.GesturePoint;
 import android.gesture.GestureStroke;
 import android.gesture.Prediction;
+import android.graphics.Rect;
 import android.os.Handler;
+import android.os.SystemClock;
 import android.util.Slog;
 import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicy;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 
-import com.android.server.input.InputFilter;
 import com.android.internal.R;
+import com.android.server.input.InputFilter;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -47,17 +46,18 @@
  * and consuming certain events. The interaction model is:
  *
  * <ol>
- *   <li>1. One finger moving around performs touch exploration.</li>
- *   <li>2. Two close fingers moving in the same direction perform a drag.</li>
- *   <li>3. Multi-finger gestures are delivered to view hierarchy.</li>
- *   <li>4. Pointers that have not moved more than a specified distance after they
+ *   <li>1. One finger moving slow around performs touch exploration.</li>
+ *   <li>2. One finger moving fast around performs gestures.</li>
+ *   <li>3. Two close fingers moving in the same direction perform a drag.</li>
+ *   <li>4. Multi-finger gestures are delivered to view hierarchy.</li>
+ *   <li>5. Pointers that have not moved more than a specified distance after they
  *          went down are considered inactive.</li>
- *   <li>5. Two fingers moving too far from each other or in different directions
- *          are considered a multi-finger gesture.</li>
- *   <li>6. Tapping on the last touch explored location within given time and
- *          distance slop performs a click.</li>
- *   <li>7. Tapping and holding for a while on the last touch explored location within
- *          given time and distance slop performs a long press.</li>
+ *   <li>6. Two fingers moving in different directions are considered a multi-finger gesture.</li>
+ *   <li>7. Double tapping clicks on the on the last touch explored location of it was in
+ *          a window that does not take focus, otherwise the click is within the accessibility
+ *          focused rectangle.</li>
+ *   <li>7. Tapping and holding for a while performs a long press in a similar fashion
+ *          as the click above.</li>
  * <ol>
  *
  * @hide
@@ -75,85 +75,116 @@
     private static final int STATE_DELEGATING = 0x00000004;
     private static final int STATE_GESTURE_DETECTING = 0x00000005;
 
-    // The time slop in milliseconds for activating an item after it has
-    // been touch explored. Tapping on an item within this slop will perform
-    // a click and tapping and holding down a long press.
-    private static final long ACTIVATION_TIME_SLOP = 2000;
-
     // The minimum of the cosine between the vectors of two moving
     // pointers so they can be considered moving in the same direction.
     private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
 
-    // The delay for sending a hover enter event.
-    private static final long DELAY_SEND_HOVER_ENTER = 200;
-
     // Constant referring to the ids bits of all pointers.
     private static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF;
 
     // This constant captures the current implementation detail that
     // pointer IDs are between 0 and 31 inclusive (subject to change).
     // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
-    public static final int MAX_POINTER_COUNT = 32;
+    private static final int MAX_POINTER_COUNT = 32;
 
     // Invalid pointer ID.
-    public static final int INVALID_POINTER_ID = -1;
+    private static final int INVALID_POINTER_ID = -1;
+
+    // The velocity above which we detect gestures.
+    private static final int GESTURE_DETECTION_VELOCITY_DIP = 1000;
+
+    // The minimal distance before we take the middle of the distance between
+    // the two dragging pointers as opposed to use the location of the primary one.
+    private static final int MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP = 200;
 
     // Temporary array for storing pointer IDs.
     private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
 
-    // The distance from the last touch explored location tapping within
-    // which would perform a click and tapping and holding a long press.
-    private final int mTouchExplorationTapSlop;
+    // Timeout within which we try to detect a tap.
+    private final int mTapTimeout;
+
+    // Timeout within which we try to detect a double tap.
+    private final int mDoubleTapTimeout;
+
+    // Slop between the down and up tap to be a tap.
+    private final int mTouchSlop;
+
+    // Slop between the first and second tap to be a double tap.
+    private final int mDoubleTapSlop;
 
     // The InputFilter this tracker is associated with i.e. the filter
     // which delegates event processing to this touch explorer.
     private final InputFilter mInputFilter;
 
-    // Handle to the accessibility manager for firing accessibility events
-    // announcing touch exploration gesture start and end.
-    private final AccessibilityManager mAccessibilityManager;
-
-    // The last event that was received while performing touch exploration.
-    private MotionEvent mLastTouchExploreEvent;
-
     // The current state of the touch explorer.
     private int mCurrentState = STATE_TOUCH_EXPLORING;
 
-    // Flag whether a touch exploration gesture is in progress.
-    private boolean mTouchExploreGestureInProgress;
-
     // The ID of the pointer used for dragging.
     private int mDraggingPointerId;
 
     // Handler for performing asynchronous operations.
     private final Handler mHandler;
 
-    // Command for delayed sending of a hover event.
-    private final SendHoverDelayed mSendHoverDelayed;
+    // Command for delayed sending of a hover enter event.
+    private final SendHoverDelayed mSendHoverEnterDelayed;
+
+    // Command for delayed sending of a hover exit event.
+    private final SendHoverDelayed mSendHoverExitDelayed;
 
     // Command for delayed sending of a long press.
     private final PerformLongPressDelayed mPerformLongPressDelayed;
 
+    // Helper to detect and react to double tap in touch explore mode.
+    private final DoubleTapDetector mDoubleTapDetector;
+
+    // The scaled minimal distance before we take the middle of the distance between
+    // the two dragging pointers as opposed to use the location of the primary one.
+    private final int mScaledMinPointerDistanceToUseMiddleLocation;
+
+    // The scaled velocity above which we detect gestures.
+    private final int mScaledGestureDetectionVelocity;
+
+    // Helper to track gesture velocity.
     private VelocityTracker mVelocityTracker;
 
+    // Helper class to track received pointers.
     private final ReceivedPointerTracker mReceivedPointerTracker;
 
+    // Helper class to track injected pointers.
     private final InjectedPointerTracker mInjectedPointerTracker;
 
-    private final GestureListener mGestureListener;
+    // Handle to the accessibility manager service.
+    private final AccessibilityManagerService mAms;
 
-    /**
-     * Callback for gesture detection.
-     */
-    public interface GestureListener {
+    // Temporary rectangle to avoid instantiation.
+    private final Rect mTempRect = new Rect();
 
-        /**
-         * Called when a given gesture was performed.
-         *
-         * @param gestureId The gesture id.
-         */
-        public boolean onGesture(int gestureId);
-    }
+    // The X of the previous event.
+    private float mPreviousX;
+
+    // The Y of the previous event.
+    private float mPreviousY;
+
+    // Buffer for storing points for gesture detection.
+    private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
+
+    // The minimal delta between moves to add a gesture point.
+    private static final int TOUCH_TOLERANCE = 3;
+
+    // The minimal score for accepting a predicted gesture.
+    private static final float MIN_PREDICTION_SCORE = 2.0f;
+
+    // The library for gesture detection.
+    private GestureLibrary mGestureLibrary;
+
+    // The long pressing pointer id if coordinate remapping is needed.
+    private int mLongPressingPointerId;
+
+    // The long pressing pointer X if coordinate remapping is needed.
+    private int mLongPressingPointerDeltaX;
+
+    // The long pressing pointer Y if coordinate remapping is needed.
+    private int mLongPressingPointerDeltaY;
 
     /**
      * Creates a new instance.
@@ -162,25 +193,73 @@
      * @param context A context handle for accessing resources.
      */
     public TouchExplorer(InputFilter inputFilter, Context context,
-            GestureListener gestureListener) {
-        mGestureListener = gestureListener;
+            AccessibilityManagerService service) {
+        mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker(context);
         mInjectedPointerTracker = new InjectedPointerTracker();
         mInputFilter = inputFilter;
-        mTouchExplorationTapSlop =
-            ViewConfiguration.get(context).getScaledTouchExploreTapSlop();
+        mTapTimeout = ViewConfiguration.getTapTimeout();
+        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
         mHandler = new Handler(context.getMainLooper());
-        mSendHoverDelayed = new SendHoverDelayed();
         mPerformLongPressDelayed = new PerformLongPressDelayed();
-        mAccessibilityManager = AccessibilityManager.getInstance(context);
         mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
         mGestureLibrary.setOrientationStyle(4);
         mGestureLibrary.load();
+        mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
+        mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
+        mDoubleTapDetector = new DoubleTapDetector();
+        final float density = context.getResources().getDisplayMetrics().density;
+        mScaledMinPointerDistanceToUseMiddleLocation =
+            (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
+        mScaledGestureDetectionVelocity = (int) (GESTURE_DETECTION_VELOCITY_DIP * density);
+    }
+
+    public void clear() {
+        // If we have not received an event then we are in initial
+        // state. Therefore, there is not need to clean anything.
+        MotionEvent event = mReceivedPointerTracker.getLastReceivedEvent();
+        if (event != null) {
+            clear(mReceivedPointerTracker.getLastReceivedEvent(), WindowManagerPolicy.FLAG_TRUSTED);
+        }
     }
 
     public void clear(MotionEvent event, int policyFlags) {
-        sendUpForInjectedDownPointers(event, policyFlags);
-        clear();
+        switch (mCurrentState) {
+            case STATE_TOUCH_EXPLORING: {
+                // If a touch exploration gesture is in progress send events for its end.
+                sendExitEventsIfNeeded(policyFlags);
+            } break;
+            case STATE_DRAGGING: {
+                mDraggingPointerId = INVALID_POINTER_ID;
+                // Send exit to all pointers that we have delivered.
+                sendUpForInjectedDownPointers(event, policyFlags);
+            } break;
+            case STATE_DELEGATING: {
+                // Send exit to all pointers that we have delivered.
+                sendUpForInjectedDownPointers(event, policyFlags);
+            } break;
+            case STATE_GESTURE_DETECTING: {
+                // Clear the current stroke.
+                mStrokeBuffer.clear();
+            } break;
+        }
+        // Remove all pending callbacks.
+        mSendHoverEnterDelayed.remove();
+        mSendHoverExitDelayed.remove();
+        mPerformLongPressDelayed.remove();
+        // Reset the pointer trackers.
+        mReceivedPointerTracker.clear();
+        mInjectedPointerTracker.clear();
+        // Clear the double tap detector
+        mDoubleTapDetector.clear();
+        // Go to initial state.
+        // Clear the long pressing pointer remap data.
+        mLongPressingPointerId = -1;
+        mLongPressingPointerDeltaX = 0;
+        mLongPressingPointerDeltaY = 0;
+        mCurrentState = STATE_TOUCH_EXPLORING;
     }
 
     public void onMotionEvent(MotionEvent event, int policyFlags) {
@@ -218,7 +297,6 @@
      */
     private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-        InjectedPointerTracker injectedTracker = mInjectedPointerTracker;
         final int activePointerCount = receivedTracker.getActivePointerCount();
 
         if (mVelocityTracker == null) {
@@ -226,8 +304,16 @@
         }
         mVelocityTracker.addMovement(event);
 
+        mDoubleTapDetector.onMotionEvent(event, policyFlags);
+
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
+                // Pre-feed the motion events to the gesture detector since we
+                // have a distance slop before getting into gesture detection
+                // mode and not using the points within this slop significantly
+                // decreases the quality of gesture recognition.
+                handleMotionEventGestureDetecting(event, policyFlags);
+                //$FALL-THROUGH$
             case MotionEvent.ACTION_POINTER_DOWN: {
                 switch (activePointerCount) {
                     case 0: {
@@ -235,44 +321,31 @@
                                 + "touch exploring state!");
                     }
                     case 1: {
-                        mSendHoverDelayed.remove();
-                        mPerformLongPressDelayed.remove();
-                        // Send a hover for every finger down so the user gets feedback.
+                        // If we still have not notified the user for the last
+                        // touch, we figure out what to do. If were waiting
+                        // we resent the delayed callback and wait again.
+                        if (mSendHoverEnterDelayed.isPending()) {
+                            mSendHoverEnterDelayed.remove();
+                            mSendHoverExitDelayed.remove();
+                            mPerformLongPressDelayed.remove();
+                        }
+
+                        // If we have the first tap schedule a long press and break
+                        // since we do not want to schedule hover enter because
+                        // the delayed callback will kick in before the long click.
+                        // This would lead to a state transition resulting in long
+                        // pressing the item below the double taped area which is
+                        // not necessary where accessibility focus is.
+                        if (mDoubleTapDetector.firstTapDetected()) {
+                            // We got a tap now post a long press action.
+                            mPerformLongPressDelayed.post(event, policyFlags);
+                            break;
+                        }
+                        // Deliver hover enter with a delay to have a chance
+                        // to detect what the user is trying to do.
                         final int pointerId = receivedTracker.getPrimaryActivePointerId();
                         final int pointerIdBits = (1 << pointerId);
-                        final int lastAction = injectedTracker.getLastInjectedHoverAction();
-
-                        // Deliver hover enter with a delay to have a change to detect
-                        // whether the user actually starts a scrolling gesture.
-                        if (lastAction == MotionEvent.ACTION_HOVER_EXIT) {
-                            mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER,
-                                    pointerIdBits, policyFlags, DELAY_SEND_HOVER_ENTER);
-                        } else {
-                            sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
-                                    policyFlags);
-                        }
-
-                        if (mLastTouchExploreEvent == null) {
-                            break;
-                        }
-
-                        // If more pointers down on the screen since the last touch
-                        // exploration we discard the last cached touch explore event.
-                        if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) {
-                            mLastTouchExploreEvent = null;
-                            break;
-                        }
-
-                        // If the down is in the time slop => schedule a long press.
-                        final long pointerDownTime =
-                            receivedTracker.getReceivedPointerDownTime(pointerId);
-                        final long lastExploreTime = mLastTouchExploreEvent.getEventTime();
-                        final long deltaTimeExplore = pointerDownTime - lastExploreTime;
-                        if (deltaTimeExplore <= ACTIVATION_TIME_SLOP) {
-                            mPerformLongPressDelayed.post(event, policyFlags,
-                                    ViewConfiguration.getLongPressTimeout());
-                            break;
-                        }
+                        mSendHoverEnterDelayed.post(event, pointerIdBits, policyFlags);
                     } break;
                     default: {
                         /* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -288,119 +361,130 @@
                         /* do nothing - no active pointers so we swallow the event */
                     } break;
                     case 1: {
-                        // Detect touch exploration gesture start by having one active pointer
-                        // that moved more than a given distance.
-                        if (!mTouchExploreGestureInProgress) {
+                        // We have not started sending events since we try to
+                        // figure out what the user is doing.
+                        if (mSendHoverEnterDelayed.isPending()) {
+                            // Pre-feed the motion events to the gesture detector since we
+                            // have a distance slop before getting into gesture detection
+                            // mode and not using the points within this slop significantly
+                            // decreases the quality of gesture recognition.
+                            handleMotionEventGestureDetecting(event, policyFlags);
+
                             final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
                                 - event.getX(pointerIndex);
                             final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
                                 - event.getY(pointerIndex);
                             final double moveDelta = Math.hypot(deltaX, deltaY);
-
-                            if (moveDelta > mTouchExplorationTapSlop) {
-
+                            // The user has moved enough for us to decide.
+                            if (moveDelta > mDoubleTapSlop) {
+                                // Check whether the user is performing a gesture. We
+                                // detect gestures if the pointer is moving above a
+                                // given velocity.
                                 mVelocityTracker.computeCurrentVelocity(1000);
                                 final float maxAbsVelocity = Math.max(
                                         Math.abs(mVelocityTracker.getXVelocity(pointerId)),
                                         Math.abs(mVelocityTracker.getYVelocity(pointerId)));
-                                // TODO: Tune the velocity cut off and add a constant.
-                                if (maxAbsVelocity > 1000) {
-                                    clear(event, policyFlags);
+                                if (maxAbsVelocity > mScaledGestureDetectionVelocity) {
+                                    // We have to perform gesture detection, so
+                                    // clear the current state and try to detect.
                                     mCurrentState = STATE_GESTURE_DETECTING;
-                                    event.setAction(MotionEvent.ACTION_DOWN);
-                                    handleMotionEventGestureDetecting(event, policyFlags);
-                                    return;
-                                }
-
-                                mTouchExploreGestureInProgress = true;
-                                sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
-                                // Make sure the scheduled down/move event is sent.
-                                mSendHoverDelayed.forceSendAndRemove();
-                                mPerformLongPressDelayed.remove();
-                                // If we have transitioned to exploring state from another one
-                                // we need to send a hover enter event here.
-                                final int lastAction = injectedTracker.getLastInjectedHoverAction();
-                                if (lastAction == MotionEvent.ACTION_HOVER_EXIT) {
-                                    sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER,
+                                    mSendHoverEnterDelayed.remove();
+                                    mSendHoverExitDelayed.remove();
+                                    mPerformLongPressDelayed.remove();
+                                } else {
+                                    // We have just decided that the user is touch,
+                                    // exploring so start sending events.
+                                    mSendHoverEnterDelayed.forceSendAndRemove();
+                                    mSendHoverExitDelayed.remove();
+                                    sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                             pointerIdBits, policyFlags);
                                 }
-                                sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
-                                        policyFlags);
+                                break;
                             }
                         } else {
-                            // Touch exploration gesture in progress so send a hover event.
+                            // The user is wither double tapping or performing long
+                            // press so do not send move events yet.
+                            if (mDoubleTapDetector.firstTapDetected()) {
+                                break;
+                            }
+                            sendEnterEventsIfNeeded(policyFlags);
                             sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
                                     policyFlags);
                         }
-
-                        // If the exploring pointer moved enough => cancel the long press.
-                        if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null
-                                && mPerformLongPressDelayed.isPenidng()) {
-
-                            // If the pointer moved more than the tap slop => cancel long press.
-                            final float deltaX = mLastTouchExploreEvent.getX(pointerIndex)
-                                    - event.getX(pointerIndex);
-                            final float deltaY = mLastTouchExploreEvent.getY(pointerIndex)
-                                    - event.getY(pointerIndex);
-                            final float moveDelta = (float) Math.hypot(deltaX, deltaY);
-                            if (moveDelta > mTouchExplorationTapSlop) {
-                                mLastTouchExploreEvent = null;
-                                mPerformLongPressDelayed.remove();
-                                break;
-                            }
-                        }
                     } break;
                     case 2: {
-                        mSendHoverDelayed.remove();
-                        mPerformLongPressDelayed.remove();
-                        // We want to no longer hover over the location so subsequent
-                        // touch at the same spot will generate a hover enter.
-                        ensureHoverExitSent(event, pointerIdBits, policyFlags);
+                        // More than one pointer so the user is not touch exploring
+                        // and now we have to decide whether to delegate or drag.
+                        if (mSendHoverEnterDelayed.isPending()) {
+                            // We have not started sending events so cancel
+                            // scheduled sending events.
+                            mSendHoverEnterDelayed.remove();
+                            mSendHoverExitDelayed.remove();
+                            mPerformLongPressDelayed.remove();
+                        } else {
+                            // If the user is touch exploring the second pointer may be
+                            // performing a double tap to activate an item without need
+                            // for the user to lift his exploring finger.
+                            final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
+                                    - event.getX(pointerIndex);
+                            final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
+                                    - event.getY(pointerIndex);
+                            final double moveDelta = Math.hypot(deltaX, deltaY);
+                            if (moveDelta < mDoubleTapSlop) {
+                                break;
+                            }
+                            // We are sending events so send exit and gesture
+                            // end since we transition to another state.
+                            sendExitEventsIfNeeded(policyFlags);
+                        }
+
+                        // We know that a new state transition is to happen and the
+                        // new state will not be gesture recognition, so clear the
+                        // stashed gesture strokes.
+                        mStrokeBuffer.clear();
 
                         if (isDraggingGesture(event)) {
                             // Two pointers moving in the same direction within
                             // a given distance perform a drag.
+                            mSendHoverEnterDelayed.remove();
+                            mSendHoverExitDelayed.remove();
+                            mPerformLongPressDelayed.remove();
                             mCurrentState = STATE_DRAGGING;
-                            if (mTouchExploreGestureInProgress) {
-                                sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
-                                mTouchExploreGestureInProgress = false;
-                            }
-                            mLastTouchExploreEvent = null;
                             mDraggingPointerId = pointerId;
                             sendMotionEvent(event, MotionEvent.ACTION_DOWN, pointerIdBits,
                                     policyFlags);
                         } else {
                             // Two pointers moving arbitrary are delegated to the view hierarchy.
                             mCurrentState = STATE_DELEGATING;
-                            mSendHoverDelayed.remove();
-                            if (mTouchExploreGestureInProgress) {
-                                sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
-                                mTouchExploreGestureInProgress = false;
-                            }
-                            mLastTouchExploreEvent = null;
                             sendDownForAllActiveNotInjectedPointers(event, policyFlags);
                         }
                     } break;
                     default: {
-                        mSendHoverDelayed.remove();
-                        mPerformLongPressDelayed.remove();
-                        // We want to no longer hover over the location so subsequent
-                        // touch at the same spot will generate a hover enter.
-                        ensureHoverExitSent(event, pointerIdBits, policyFlags);
+                        // More than one pointer so the user is not touch exploring
+                        // and now we have to decide whether to delegate or drag.
+                        if (mSendHoverEnterDelayed.isPending()) {
+                            // We have not started sending events so cancel
+                            // scheduled sending events.
+                            mSendHoverEnterDelayed.remove();
+                            mSendHoverExitDelayed.remove();
+                            mPerformLongPressDelayed.remove();
+                        } else {
+                            // We are sending events so send exit and gesture
+                            // end since we transition to another state.
+                            sendExitEventsIfNeeded(policyFlags);
+                        }
 
                         // More than two pointers are delegated to the view hierarchy.
                         mCurrentState = STATE_DELEGATING;
-                        mSendHoverDelayed.remove();
-                        if (mTouchExploreGestureInProgress) {
-                            sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
-                            mTouchExploreGestureInProgress = false;
-                        }
-                        mLastTouchExploreEvent = null;
                         sendDownForAllActiveNotInjectedPointers(event, policyFlags);
                     }
                 }
             } break;
             case MotionEvent.ACTION_UP:
+                // We know that we do not need the pre-fed gesture points are not
+                // needed anymore since the last pointer just went up.
+                mStrokeBuffer.clear();
+                //$FALL-THROUGH$
             case MotionEvent.ACTION_POINTER_UP: {
                 final int pointerId = receivedTracker.getLastReceivedUpPointerId();
                 final int pointerIdBits = (1 << pointerId);
@@ -413,59 +497,12 @@
 
                         mPerformLongPressDelayed.remove();
 
-                        // If touch exploring announce the end of the gesture.
-                        // Also do not click on the last explored location.
-                        if (mTouchExploreGestureInProgress) {
-                            mTouchExploreGestureInProgress = false;
-                            mSendHoverDelayed.forceSendAndRemove();
-                            ensureHoverExitSent(event, pointerIdBits, policyFlags);
-                            mLastTouchExploreEvent = MotionEvent.obtain(event);
-                            sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
-                            break;
-                        }
-
-                        // Detect whether to activate i.e. click on the last explored location.
-                        if (mLastTouchExploreEvent != null) {
-                            // If the down was not in the time slop => nothing else to do.
-                            final long eventTime =
-                                receivedTracker.getLastReceivedUpPointerDownTime();
-                            final long exploreTime = mLastTouchExploreEvent.getEventTime();
-                            final long deltaTime = eventTime - exploreTime;
-                            if (deltaTime > ACTIVATION_TIME_SLOP) {
-                                mSendHoverDelayed.forceSendAndRemove();
-                                ensureHoverExitSent(event, pointerIdBits, policyFlags);
-                                mLastTouchExploreEvent = MotionEvent.obtain(event);
-                                break;
-                            }
-
-                            // If a tap is farther than the tap slop => nothing to do.
-                            final int pointerIndex = event.findPointerIndex(pointerId);
-                            final float deltaX = mLastTouchExploreEvent.getX(pointerIndex)
-                                    - event.getX(pointerIndex);
-                            final float deltaY = mLastTouchExploreEvent.getY(pointerIndex)
-                                    - event.getY(pointerIndex);
-                            final float deltaMove = (float) Math.hypot(deltaX, deltaY);
-                            if (deltaMove > mTouchExplorationTapSlop) {
-                                mSendHoverDelayed.forceSendAndRemove();
-                                ensureHoverExitSent(event, pointerIdBits, policyFlags);
-                                mLastTouchExploreEvent = MotionEvent.obtain(event);
-                                break;
-                            }
-
-                            // This is a tap so do not send hover events since
-                            // this events will result in firing the corresponding
-                            // accessibility events confusing the user about what
-                            // is actually clicked.
-                            mSendHoverDelayed.remove();
-                            ensureHoverExitSent(event, pointerIdBits, policyFlags);
-
-                            // All preconditions are met, so click the last explored location.
-                            sendActionDownAndUp(mLastTouchExploreEvent, policyFlags);
-                            mLastTouchExploreEvent = null;
+                        // If we have not delivered the enter schedule exit.
+                        if (mSendHoverEnterDelayed.isPending()) {
+                            mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
                         } else {
-                            mSendHoverDelayed.forceSendAndRemove();
-                            ensureHoverExitSent(event, pointerIdBits, policyFlags);
-                            mLastTouchExploreEvent = MotionEvent.obtain(event);
+                            // The user is touch exploring so we send events for end.
+                            sendExitEventsIfNeeded(policyFlags);
                         }
                     } break;
                 }
@@ -475,16 +512,7 @@
                 }
             } break;
             case MotionEvent.ACTION_CANCEL: {
-                mSendHoverDelayed.remove();
-                mPerformLongPressDelayed.remove();
-                final int pointerId = receivedTracker.getPrimaryActivePointerId();
-                final int pointerIdBits = (1 << pointerId);                
-                ensureHoverExitSent(event, pointerIdBits, policyFlags);
-                clear();
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.clear();
-                    mVelocityTracker = null;
-                }
+                clear(event, policyFlags);
             } break;
         }
     }
@@ -517,6 +545,28 @@
                     } break;
                     case 2: {
                         if (isDraggingGesture(event)) {
+                            // If the dragging pointer are closer that a given distance we
+                            // use the location of the primary one. Otherwise, we take the
+                            // middle between the pointers.
+                            int[] pointerIds = mTempPointerIds;
+                            mReceivedPointerTracker.populateActivePointerIds(pointerIds);
+
+                            final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
+                            final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
+
+                            final float firstPtrX = event.getX(firstPtrIndex);
+                            final float firstPtrY = event.getY(firstPtrIndex);
+                            final float secondPtrX = event.getX(secondPtrIndex);
+                            final float secondPtrY = event.getY(secondPtrIndex);
+
+                            final float deltaX = firstPtrX - secondPtrX;
+                            final float deltaY = firstPtrY - secondPtrY;
+                            final double distance = Math.hypot(deltaX, deltaY);
+
+                            if (distance > mScaledMinPointerDistanceToUseMiddleLocation) {
+                                event.setLocation(deltaX / 2, deltaY / 2);
+                            }
+
                             // If still dragging send a drag event.
                             sendMotionEvent(event, MotionEvent.ACTION_MOVE, pointerIdBits,
                                     policyFlags);
@@ -557,7 +607,7 @@
                 mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
-                clear();
+                clear(event, policyFlags);
             } break;
         }
     }
@@ -574,9 +624,6 @@
                 throw new IllegalStateException("Delegating state can only be reached if "
                         + "there is at least one pointer down!");
             }
-            case MotionEvent.ACTION_UP: {
-                mCurrentState = STATE_TOUCH_EXPLORING;
-            } break;
             case MotionEvent.ACTION_MOVE: {
                 // Check  whether some other pointer became active because they have moved
                 // a given distance and if such exist send them to the view hierarchy
@@ -587,30 +634,24 @@
                     sendDownForAllActiveNotInjectedPointers(prototype, policyFlags);
                 }
             } break;
+            case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_POINTER_UP: {
+                mLongPressingPointerId = -1;
+                mLongPressingPointerDeltaX = 0;
+                mLongPressingPointerDeltaY = 0;
                 // No active pointers => go to initial state.
                 if (mReceivedPointerTracker.getActivePointerCount() == 0) {
                     mCurrentState = STATE_TOUCH_EXPLORING;
                 }
             } break;
             case MotionEvent.ACTION_CANCEL: {
-                clear();
+                clear(event, policyFlags);
             } break;
         }
         // Deliver the event striping out inactive pointers.
         sendMotionEventStripInactivePointers(event, policyFlags);
     }
 
-    private float mPreviousX;
-    private float mPreviousY;
-
-    private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
-
-    private static final int TOUCH_TOLERANCE = 3;
-    private static final float MIN_PREDICTION_SCORE = 2.0f;
-
-    private GestureLibrary mGestureLibrary;
-
     private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
@@ -631,8 +672,7 @@
                     mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
                 }
             } break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_UP: {
                 float x = event.getX();
                 float y = event.getY();
                 mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
@@ -650,7 +690,7 @@
                         }
                         try {
                             final int gestureId = Integer.parseInt(bestPrediction.name);
-                            mGestureListener.onGesture(gestureId);
+                            mAms.onGesture(gestureId);
                         } catch (NumberFormatException nfe) {
                             Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
                         }
@@ -661,8 +701,7 @@
                 mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
-                mStrokeBuffer.clear();
-                mCurrentState = STATE_TOUCH_EXPLORING;
+                clear(event, policyFlags);
             } break;
         }
     }
@@ -706,17 +745,32 @@
     }
 
     /**
-     * Ensures that hover exit has been sent.
+     * Sends the exit events if needed. Such events are hover exit and touch explore
+     * gesture end.
      *
-     * @param prototype The prototype from which to create the injected events.
-     * @param pointerIdBits The bits of the pointers to send.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void ensureHoverExitSent(MotionEvent prototype, int pointerIdBits, int policyFlags) {
-        final int lastAction = mInjectedPointerTracker.getLastInjectedHoverAction();
-        if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
-            sendMotionEvent(prototype, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
-                    policyFlags);
+    private void sendExitEventsIfNeeded(int policyFlags) {
+        MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
+        if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
+            final int pointerIdBits = event.getPointerIdBits();
+            mAms.touchExplorationGestureEnded();
+            sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
+        }
+    }
+
+    /**
+     * Sends the enter events if needed. Such events are hover enter and touch explore
+     * gesture start.
+     *
+     * @param policyFlags The policy flags associated with the event.
+     */
+    private void sendEnterEventsIfNeeded(int policyFlags) {
+        MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
+        if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
+            final int pointerIdBits = event.getPointerIdBits();
+            mAms.touchExplorationGestureStarted();
+            sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
         }
     }
 
@@ -826,6 +880,36 @@
             event.setDownTime(mInjectedPointerTracker.getLastInjectedDownEventTime());
         }
 
+        // If the user is long pressing but the long pressing pointer
+        // was not exactly over the accessibility focused item we need
+        // to remap the location of that pointer so the user does not
+        // have to explicitly touch explore something to be able to
+        // long press it, or even worse to avoid the user long pressing
+        // on the wrong item since click and long press behave differently.
+        if (mLongPressingPointerId >= 0) {
+            final int remappedIndex = event.findPointerIndex(mLongPressingPointerId);
+            final int pointerCount = event.getPointerCount();
+            PointerProperties[] props = PointerProperties.createArray(pointerCount);
+            PointerCoords[] coords = PointerCoords.createArray(pointerCount);
+            for (int i = 0; i < pointerCount; i++) {
+                event.getPointerProperties(i, props[i]);
+                event.getPointerCoords(i, coords[i]);
+                if (i == remappedIndex) {
+                    coords[i].x -= mLongPressingPointerDeltaX;
+                    coords[i].y -= mLongPressingPointerDeltaY;
+                }
+            }
+            MotionEvent remapped = MotionEvent.obtain(event.getDownTime(),
+                    event.getEventTime(), event.getAction(), event.getPointerCount(),
+                    props, coords, event.getMetaState(), event.getButtonState(),
+                    1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
+                    event.getSource(), event.getFlags());
+            if (event != prototype) {
+                event.recycle();
+            }
+            event = remapped;
+        }
+
         if (DEBUG) {
             Slog.d(LOG_TAG, "Injecting event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
@@ -878,6 +962,172 @@
         }
     }
 
+    private class DoubleTapDetector {
+        private MotionEvent mDownEvent;
+        private MotionEvent mFirstTapEvent;
+
+        public void onMotionEvent(MotionEvent event, int policyFlags) {
+            final int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                case MotionEvent.ACTION_POINTER_DOWN: {
+                    if (mFirstTapEvent != null && !isSamePointerContext(mFirstTapEvent, event)) {
+                        clear();
+                    }
+                    mDownEvent = MotionEvent.obtain(event);
+                } break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_POINTER_UP: {
+                    if (mDownEvent == null) {
+                        return;
+                    }
+                    if (!isSamePointerContext(mDownEvent, event)) {
+                        clear();
+                        return;
+                    }
+                    if (isTap(mDownEvent, event)) {
+                        if (mFirstTapEvent == null || isTimedOut(mFirstTapEvent, event,
+                                mDoubleTapTimeout)) {
+                            mFirstTapEvent = MotionEvent.obtain(event);
+                            mDownEvent.recycle();
+                            mDownEvent = null;
+                            return;
+                        }
+                        if (isDoubleTap(mFirstTapEvent, event)) {
+                            onDoubleTap(event, policyFlags);
+                            mFirstTapEvent.recycle();
+                            mFirstTapEvent = null;
+                            mDownEvent.recycle();
+                            mDownEvent = null;
+                            return;
+                        }
+                        mFirstTapEvent.recycle();
+                        mFirstTapEvent = null;
+                    } else {
+                        if (mFirstTapEvent != null) {
+                            mFirstTapEvent.recycle();
+                            mFirstTapEvent = null;
+                        }
+                    }
+                    mDownEvent.recycle();
+                    mDownEvent = null;
+                } break;
+            }
+        }
+
+        public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
+            // This should never be called when more than two pointers are down.
+            if (secondTapUp.getPointerCount() > 2) {
+                return;
+            }
+
+            // Remove pending event deliveries.
+            mSendHoverEnterDelayed.remove();
+            mSendHoverExitDelayed.remove();
+            mPerformLongPressDelayed.remove();
+
+            // This is a tap so do not send hover events since
+            // this events will result in firing the corresponding
+            // accessibility events confusing the user about what
+            // is actually clicked.
+            sendExitEventsIfNeeded(policyFlags);
+
+            // If the last touched explored location is not within the focused
+            // window we will click at that exact spot, otherwise we find the
+            // accessibility focus and if the tap is within its bounds we click
+            // there, otherwise we pick the middle of the focus rectangle.
+            MotionEvent lastEvent = mInjectedPointerTracker.getLastInjectedHoverEvent();
+            if (lastEvent == null) {
+                return;
+            }
+
+            final int exploreLocationX = (int) lastEvent.getX(lastEvent.getActionIndex());
+            final int exploreLocationY = (int) lastEvent.getY(lastEvent.getActionIndex());
+
+            Rect bounds = mTempRect;
+            boolean useLastHoverLocation = false;
+
+            final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
+            final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
+            if (mAms.getAccessibilityFocusBounds(exploreLocationX, exploreLocationY, bounds)) {
+                // If the user's last touch explored location is not
+                // within the accessibility focus bounds we use the center
+                // of the accessibility focused rectangle.
+                if (!bounds.contains((int) secondTapUp.getX(pointerIndex),
+                        (int) secondTapUp.getY(pointerIndex))) {
+                    useLastHoverLocation = true;
+                }
+            }
+
+            // Do the click.
+            PointerProperties[] properties = new PointerProperties[1];
+            properties[0] = new PointerProperties();
+            secondTapUp.getPointerProperties(pointerIndex, properties[0]);
+            PointerCoords[] coords = new PointerCoords[1];
+            coords[0] = new PointerCoords();
+            coords[0].x = (useLastHoverLocation) ? bounds.centerX() : exploreLocationX;
+            coords[0].y = (useLastHoverLocation) ? bounds.centerY() : exploreLocationY;
+            MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
+                    secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
+                    coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
+                    secondTapUp.getSource(), secondTapUp.getFlags());
+            sendActionDownAndUp(event, policyFlags);
+            event.recycle();
+        }
+
+        public void clear() {
+            if (mDownEvent != null) {
+                mDownEvent.recycle();
+                mDownEvent = null;
+            }
+            if (mFirstTapEvent != null) {
+                mFirstTapEvent.recycle();
+                mFirstTapEvent = null;
+            }
+        }
+
+        public boolean isTap(MotionEvent down, MotionEvent up) {
+            return eventsWithinTimeoutAndDistance(down, up, mTapTimeout, mTouchSlop);
+        }
+
+        private boolean isDoubleTap(MotionEvent firstUp, MotionEvent secondUp) {
+            return eventsWithinTimeoutAndDistance(firstUp, secondUp, mDoubleTapTimeout,
+                    mDoubleTapSlop);
+        }
+
+        private boolean eventsWithinTimeoutAndDistance(MotionEvent first, MotionEvent second,
+                int timeout, int distance) {
+            if (isTimedOut(first, second, timeout)) {
+                return false;
+            }
+            final int downPtrIndex = first.getActionIndex();
+            final int upPtrIndex = second.getActionIndex();
+            final float deltaX = second.getX(upPtrIndex) - first.getX(downPtrIndex);
+            final float deltaY = second.getY(upPtrIndex) - first.getY(downPtrIndex);
+            final double deltaMove = Math.hypot(deltaX, deltaY);
+            if (deltaMove >= distance) {
+                return false;
+            }
+            return true;
+        }
+
+        private boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
+            final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
+            return (deltaTime >= timeout);
+        }
+
+        private boolean isSamePointerContext(MotionEvent first, MotionEvent second) {
+            return (first.getPointerIdBits() == second.getPointerIdBits()
+                    && first.getPointerId(first.getActionIndex())
+                            == second.getPointerId(second.getActionIndex()));
+        }
+
+        public boolean firstTapDetected() {
+            return mFirstTapEvent != null
+                && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
+        }
+    }
+
     /**
      * Determines whether a two pointer gesture is a dragging one.
      *
@@ -940,30 +1190,6 @@
         return true;
     }
 
-   /**
-    * Sends an event announcing the start/end of a touch exploration gesture.
-    *
-    * @param eventType The type of the event to send.
-    */
-    private void sendAccessibilityEvent(int eventType) {
-        AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-        mAccessibilityManager.sendAccessibilityEvent(event);
-    }
-
-    /**
-     * Clears the internal state of this explorer.
-     */
-    public void clear() {
-        mSendHoverDelayed.remove();
-        mPerformLongPressDelayed.remove();
-        mReceivedPointerTracker.clear();
-        mInjectedPointerTracker.clear();
-        mLastTouchExploreEvent = null;
-        mCurrentState = STATE_TOUCH_EXPLORING;
-        mTouchExploreGestureInProgress = false;
-        mDraggingPointerId = INVALID_POINTER_ID;
-    }
-
     /**
      * Gets the symbolic name of a state.
      *
@@ -1002,10 +1228,10 @@
         private MotionEvent mEvent;
         private int mPolicyFlags;
 
-        public void post(MotionEvent prototype, int policyFlags, long delay) {
+        public void post(MotionEvent prototype, int policyFlags) {
             mEvent = MotionEvent.obtain(prototype);
             mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, delay);
+            mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
         }
 
         public void remove() {
@@ -1021,16 +1247,29 @@
 
         @Override
         public void run() {
-            mCurrentState = STATE_DELEGATING;
-            // Make sure the scheduled hover exit is delivered.
-            mSendHoverDelayed.remove();
+            final int pointerIndex = mEvent.getActionIndex();
+            final int eventX = (int) mEvent.getX(pointerIndex);
+            final int eventY = (int) mEvent.getY(pointerIndex);
+            Rect bounds = mTempRect;
+            if (mAms.getAccessibilityFocusBounds(eventX, eventY, bounds)
+                    && !bounds.contains(eventX, eventY)) {
+                mLongPressingPointerId = mEvent.getPointerId(pointerIndex);
+                mLongPressingPointerDeltaX = eventX - bounds.centerX();
+                mLongPressingPointerDeltaY = eventY - bounds.centerY();
+            } else {
+                mLongPressingPointerId = -1;
+                mLongPressingPointerDeltaX = 0;
+                mLongPressingPointerDeltaY = 0;
+            }
+            // We are sending events so send exit and gesture
+            // end since we transition to another state.
             final int pointerId = mReceivedPointerTracker.getPrimaryActivePointerId();
             final int pointerIdBits = (1 << pointerId);
-            ensureHoverExitSent(mEvent, pointerIdBits, mPolicyFlags);
+            mAms.touchExplorationGestureEnded();
+            sendExitEventsIfNeeded(mPolicyFlags);
 
+            mCurrentState = STATE_DELEGATING;
             sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
-            mTouchExploreGestureInProgress = false;
-            mLastTouchExploreEvent = null;
             clear();
         }
 
@@ -1047,20 +1286,41 @@
     /**
      * Class for delayed sending of hover events.
      */
-    private final class SendHoverDelayed implements Runnable {
-        private MotionEvent mEvent;
-        private int mAction;
+    class SendHoverDelayed implements Runnable {
+        private final String LOG_TAG_SEND_HOVER_DELAYED = SendHoverDelayed.class.getName();
+
+        private final int mHoverAction;
+        private final boolean mGestureStarted;
+
+        private MotionEvent mPrototype;
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public void post(MotionEvent prototype, int action, int pointerIdBits, int policyFlags,
-                long delay) {
+        public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
+            mHoverAction = hoverAction;
+            mGestureStarted = gestureStarted;
+        }
+
+        public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) {
             remove();
-            mEvent = MotionEvent.obtain(prototype);
-            mAction = action;
+            mPrototype = MotionEvent.obtain(prototype);
             mPointerIdBits = pointerIdBits;
             mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, delay);
+            mHandler.postDelayed(this, mTapTimeout);
+        }
+
+        public float getX() {
+            if (isPending()) {
+                return mPrototype.getX();
+            }
+            return 0;
+        }
+
+        public float getY() {
+            if (isPending()) {
+                return mPrototype.getY();
+            }
+            return 0;
         }
 
         public void remove() {
@@ -1068,23 +1328,22 @@
             clear();
         }
 
-        private boolean isPenidng() {
-            return (mEvent != null);
+        private boolean isPending() {
+            return (mPrototype != null);
         }
 
         private void clear() {
-            if (!isPenidng()) {
+            if (!isPending()) {
                 return;
             }
-            mEvent.recycle();
-            mEvent = null;
-            mAction = 0;
+            mPrototype.recycle();
+            mPrototype = null;
             mPointerIdBits = -1;
             mPolicyFlags = 0;
         }
 
         public void forceSendAndRemove() {
-            if (isPenidng()) {
+            if (isPending()) {
                 run();
                 remove();
             }
@@ -1092,16 +1351,17 @@
 
         public void run() {
             if (DEBUG) {
-                if (mAction == MotionEvent.ACTION_HOVER_ENTER) {
-                    Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER);
-                } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) {
-                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE");
-                } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) {
-                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT");
-                }
+                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: "
+                        + MotionEvent.actionToString(mHoverAction));
+                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
+                        "touchExplorationGestureStarted" : "touchExplorationGestureEnded");
             }
-
-            sendMotionEvent(mEvent, mAction, mPointerIdBits, mPolicyFlags);
+            if (mGestureStarted) {
+                mAms.touchExplorationGestureStarted();
+            } else {
+                mAms.touchExplorationGestureEnded();
+            }
+            sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
             clear();
         }
     }
@@ -1120,8 +1380,8 @@
         // The time of the last injected down.
         private long mLastInjectedDownEventTime;
 
-        // The action of the last injected hover event.
-        private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT;
+        // The last injected hover event.
+        private MotionEvent mLastInjectedHoverEvent;
 
         /**
          * Processes an injected {@link MotionEvent} event.
@@ -1150,11 +1410,14 @@
                 case MotionEvent.ACTION_HOVER_ENTER:
                 case MotionEvent.ACTION_HOVER_MOVE:
                 case MotionEvent.ACTION_HOVER_EXIT: {
-                    mLastInjectedHoverEventAction = event.getActionMasked();
+                    if (mLastInjectedHoverEvent != null) {
+                        mLastInjectedHoverEvent.recycle();
+                    }
+                    mLastInjectedHoverEvent = MotionEvent.obtain(event);
                 } break;
             }
             if (DEBUG) {
-                Slog.i(LOG_TAG_INJECTED_POINTER_TRACKER, "Injected pointer: " + toString());
+                Slog.i(LOG_TAG_INJECTED_POINTER_TRACKER, "Injected pointer:\n" + toString());
             }
         }
 
@@ -1198,10 +1461,10 @@
         }
 
         /**
-         * @return The action of the last injected hover event.
+         * @return The the last injected hover event.
          */
-        public int getLastInjectedHoverAction() {
-            return mLastInjectedHoverEventAction;
+        public MotionEvent getLastInjectedHoverEvent() {
+            return mLastInjectedHoverEvent;
         }
 
         @Override
@@ -1260,6 +1523,8 @@
         private float mLastReceivedUpPointerDownX;
         private float mLastReceivedUpPointerDownY;
 
+        private MotionEvent mLastReceivedEvent;
+
         /**
          * Creates a new instance.
          *
@@ -1294,6 +1559,11 @@
          * @param event The event to process.
          */
         public void onMotionEvent(MotionEvent event) {
+            if (mLastReceivedEvent != null) {
+                mLastReceivedEvent.recycle();
+            }
+            mLastReceivedEvent = MotionEvent.obtain(event);
+
             final int action = event.getActionMasked();
             switch (action) {
                 case MotionEvent.ACTION_DOWN: {
@@ -1318,6 +1588,13 @@
         }
 
         /**
+         * @return The last received event.
+         */
+        public MotionEvent getLastReceivedEvent() {
+            return mLastReceivedEvent;
+        }
+
+        /**
          * @return The number of received pointers that are down.
          */
         public int getReceivedPointerDownCount() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 76016f4..6464d7f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4639,35 +4639,12 @@
             pid = tlsIdentity.pid;
         }
 
-        // Root, system server and our own process get to do everything.
-        if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
+        if (pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
         }
-        // Isolated processes don't get any permissions.
-        if (UserId.isIsolated(uid)) {
-            return PackageManager.PERMISSION_DENIED;
-        }
-        // If there is a uid that owns whatever is being accessed, it has
-        // blanket access to it regardless of the permissions it requires.
-        if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
-            return PackageManager.PERMISSION_GRANTED;
-        }
-        // If the target is not exported, then nobody else can get to it.
-        if (!exported) {
-            Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
-            return PackageManager.PERMISSION_DENIED;
-        }
-        if (permission == null) {
-            return PackageManager.PERMISSION_GRANTED;
-        }
-        try {
-            return AppGlobals.getPackageManager()
-                    .checkUidPermission(permission, uid);
-        } catch (RemoteException e) {
-            // Should never happen, but if it does... deny!
-            Slog.e(TAG, "PackageManager is dead?!?", e);
-        }
-        return PackageManager.PERMISSION_DENIED;
+
+        return ActivityManager.checkComponentPermission(permission, uid,
+                owningUid, exported);
     }
 
     /**
@@ -13544,6 +13521,14 @@
         }
     }
 
+    public int getLaunchedFromUid(IBinder activityToken) {
+        ActivityRecord srec = ActivityRecord.forToken(activityToken);
+        if (srec == null) {
+            return -1;
+        }
+        return srec.launchedFromUid;
+    }
+
     // =========================================================
     // LIFETIME MANAGEMENT
     // =========================================================
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 9e94b52..d85facc 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -16,16 +16,16 @@
 
 package com.android.server.input;
 
-import com.android.internal.os.AtomicFile;
-import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
 import com.android.server.Watchdog;
 
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import android.Manifest;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
@@ -37,7 +37,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
@@ -71,23 +70,19 @@
 import android.view.Surface;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicy;
+import android.widget.Toast;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Map;
+import java.util.HashSet;
 
-import libcore.io.IoUtils;
 import libcore.io.Streams;
 import libcore.util.Objects;
 
@@ -96,11 +91,15 @@
  */
 public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
     static final String TAG = "InputManager";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
 
     private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
+    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
+    private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
+    private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
+    private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
 
     // Pointer to native input manager service object.
     private final int mPtr;
@@ -110,6 +109,7 @@
     private final InputManagerHandler mHandler;
     private boolean mSystemReady;
     private BluetoothService mBluetoothService;
+    private NotificationManager mNotificationManager;
 
     // Persistent data store.  Must be locked each time during use.
     private final PersistentDataStore mDataStore = new PersistentDataStore();
@@ -123,6 +123,11 @@
     private final ArrayList<InputDevicesChangedListenerRecord>
             mTempInputDevicesChangedListenersToNotify =
                     new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
+    private final ArrayList<InputDevice>
+            mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
+    private boolean mKeyboardLayoutNotificationShown;
+    private PendingIntent mKeyboardLayoutIntent;
+    private Toast mSwitchedKeyboardLayoutToast;
 
     // State for vibrator tokens.
     private Object mVibratorLock = new Object();
@@ -236,6 +241,8 @@
             Slog.d(TAG, "System ready.");
         }
         mBluetoothService = bluetoothService;
+        mNotificationManager = (NotificationManager)mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         mSystemReady = true;
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -245,10 +252,7 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Packages changed, reloading keyboard layouts.");
-                }
-                reloadKeyboardLayouts();
+                updateKeyboardLayouts();
             }
         }, filter, null, mHandler);
 
@@ -256,22 +260,25 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Bluetooth alias changed, reloading device names.");
-                }
                 reloadDeviceAliases();
             }
         }, filter, null, mHandler);
 
-        reloadKeyboardLayouts();
-        reloadDeviceAliases();
+        mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
+        mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
     }
 
     private void reloadKeyboardLayouts() {
+        if (DEBUG) {
+            Slog.d(TAG, "Reloading keyboard layouts.");
+        }
         nativeReloadKeyboardLayouts(mPtr);
     }
 
     private void reloadDeviceAliases() {
+        if (DEBUG) {
+            Slog.d(TAG, "Reloading device names.");
+        }
         nativeReloadDeviceAliases(mPtr);
     }
 
@@ -559,9 +566,11 @@
     }
 
     // Must be called on handler.
-    private void deliverInputDevicesChanged() {
+    private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
+        // Scan for changes.
+        int numFullKeyboardsAdded = 0;
         mTempInputDevicesChangedListenersToNotify.clear();
-
+        mTempFullKeyboards.clear();
         final int numListeners;
         final int[] deviceIdAndGeneration;
         synchronized (mInputDevicesLock) {
@@ -582,13 +591,126 @@
                 final InputDevice inputDevice = mInputDevices[i];
                 deviceIdAndGeneration[i * 2] = inputDevice.getId();
                 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
+
+                if (isFullKeyboard(inputDevice)) {
+                    if (!containsInputDeviceWithDescriptor(oldInputDevices,
+                            inputDevice.getDescriptor())) {
+                        mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
+                    } else {
+                        mTempFullKeyboards.add(inputDevice);
+                    }
+                }
             }
         }
 
+        // Notify listeners.
         for (int i = 0; i < numListeners; i++) {
             mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
                     deviceIdAndGeneration);
         }
+        mTempInputDevicesChangedListenersToNotify.clear();
+
+        // Check for missing keyboard layouts.
+        if (mNotificationManager != null) {
+            final int numFullKeyboards = mTempFullKeyboards.size();
+            boolean missingLayoutForExternalKeyboard = false;
+            boolean missingLayoutForExternalKeyboardAdded = false;
+            synchronized (mDataStore) {
+                for (int i = 0; i < numFullKeyboards; i++) {
+                    final InputDevice inputDevice = mTempFullKeyboards.get(i);
+                    if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) {
+                        missingLayoutForExternalKeyboard = true;
+                        if (i < numFullKeyboardsAdded) {
+                            missingLayoutForExternalKeyboardAdded = true;
+                        }
+                    }
+                }
+            }
+            if (missingLayoutForExternalKeyboard) {
+                if (missingLayoutForExternalKeyboardAdded) {
+                    showMissingKeyboardLayoutNotification();
+                }
+            } else if (mKeyboardLayoutNotificationShown) {
+                hideMissingKeyboardLayoutNotification();
+            }
+        }
+        mTempFullKeyboards.clear();
+    }
+
+    // Must be called on handler.
+    private void showMissingKeyboardLayoutNotification() {
+        if (!mKeyboardLayoutNotificationShown) {
+            if (mKeyboardLayoutIntent == null) {
+                final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mKeyboardLayoutIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+            }
+
+            Resources r = mContext.getResources();
+            Notification notification = new Notification.Builder(mContext)
+                    .setContentTitle(r.getString(
+                            R.string.select_keyboard_layout_notification_title))
+                    .setContentText(r.getString(
+                            R.string.select_keyboard_layout_notification_message))
+                    .setContentIntent(mKeyboardLayoutIntent)
+                    .setSmallIcon(R.drawable.ic_settings_language)
+                    .setPriority(Notification.PRIORITY_LOW)
+                    .build();
+            mNotificationManager.notify(R.string.select_keyboard_layout_notification_title,
+                    notification);
+            mKeyboardLayoutNotificationShown = true;
+        }
+    }
+
+    // Must be called on handler.
+    private void hideMissingKeyboardLayoutNotification() {
+        if (mKeyboardLayoutNotificationShown) {
+            mKeyboardLayoutNotificationShown = false;
+            mNotificationManager.cancel(R.string.select_keyboard_layout_notification_title);
+        }
+    }
+
+    // Must be called on handler.
+    private void updateKeyboardLayouts() {
+        // Scan all input devices state for keyboard layouts that have been uninstalled.
+        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    String descriptor, String label, String collection, int keyboardLayoutResId) {
+                availableKeyboardLayouts.add(descriptor);
+            }
+        });
+        synchronized (mDataStore) {
+            try {
+                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+
+        // Reload keyboard layouts.
+        reloadKeyboardLayouts();
+    }
+
+    private static boolean isFullKeyboard(InputDevice inputDevice) {
+        return !inputDevice.isVirtual()
+                && (inputDevice.getSources() & InputDevice.SOURCE_KEYBOARD) != 0
+                && inputDevice.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC;
+    }
+
+    private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
+            String descriptor) {
+        final int numDevices = inputDevices.length;
+        for (int i = 0; i < numDevices; i++) {
+            final InputDevice inputDevice = inputDevices[i];
+            if (inputDevice.getDescriptor().equals(descriptor)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override // Binder call
@@ -597,8 +719,8 @@
         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
             @Override
             public void visitKeyboardLayout(Resources resources,
-                    String descriptor, String label, int keyboardLayoutResId) {
-                list.add(new KeyboardLayout(descriptor, label));
+                    String descriptor, String label, String collection, int keyboardLayoutResId) {
+                list.add(new KeyboardLayout(descriptor, label, collection));
             }
         });
         return list.toArray(new KeyboardLayout[list.size()]);
@@ -614,8 +736,8 @@
         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
             @Override
             public void visitKeyboardLayout(Resources resources,
-                    String descriptor, String label, int keyboardLayoutResId) {
-                result[0] = new KeyboardLayout(descriptor, label);
+                    String descriptor, String label, String collection, int keyboardLayoutResId) {
+                result[0] = new KeyboardLayout(descriptor, label, collection);
             }
         });
         if (result[0] == null) {
@@ -663,6 +785,9 @@
             return;
         }
 
+        CharSequence receiverLabel = receiver.loadLabel(pm);
+        String collection = receiverLabel != null ? receiverLabel.toString() : "";
+
         try {
             Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
             XmlResourceParser parser = resources.getXml(configResId);
@@ -696,7 +821,7 @@
                                         receiver.packageName, receiver.name, name);
                                 if (keyboardName == null || name.equals(keyboardName)) {
                                     visitor.visitKeyboardLayout(resources, descriptor,
-                                            label, keyboardLayoutResId);
+                                            label, collection, keyboardLayoutResId);
                                 }
                             }
                         } finally {
@@ -718,43 +843,147 @@
     }
 
     @Override // Binder call
-    public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
+    public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
         if (inputDeviceDescriptor == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
         synchronized (mDataStore) {
-            return mDataStore.getKeyboardLayout(inputDeviceDescriptor);
+            return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
         }
     }
 
     @Override // Binder call
-    public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                "setKeyboardLayoutForInputDevice()")) {
+                "setCurrentKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-
         if (inputDeviceDescriptor == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
 
-        final boolean changed;
         synchronized (mDataStore) {
             try {
-                changed = mDataStore.setKeyboardLayout(
-                        inputDeviceDescriptor, keyboardLayoutDescriptor);
+                if (mDataStore.setCurrentKeyboardLayout(
+                        inputDeviceDescriptor, keyboardLayoutDescriptor)) {
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
             } finally {
                 mDataStore.saveIfNeeded();
             }
         }
+    }
 
-        if (changed) {
-            if (DEBUG) {
-                Slog.d(TAG, "Keyboard layout changed, reloading keyboard layouts.");
+    @Override // Binder call
+    public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+
+        synchronized (mDataStore) {
+            return mDataStore.getKeyboardLayouts(inputDeviceDescriptor);
+        }
+    }
+
+    @Override // Binder call
+    public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
+                "addKeyboardLayoutForInputDevice()")) {
+            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
+        }
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        synchronized (mDataStore) {
+            try {
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
+                if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor)
+                        && !Objects.equal(oldLayout,
+                                mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
             }
-            reloadKeyboardLayouts();
+        }
+    }
+
+    @Override // Binder call
+    public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
+                "removeKeyboardLayoutForInputDevice()")) {
+            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
+        }
+        if (inputDeviceDescriptor == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        synchronized (mDataStore) {
+            try {
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
+                if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor,
+                        keyboardLayoutDescriptor)
+                        && !Objects.equal(oldLayout,
+                                mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+    }
+
+    public void switchKeyboardLayout(int deviceId, int direction) {
+        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
+    }
+
+    // Must be called on handler.
+    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+        final InputDevice device = getInputDevice(deviceId);
+        final String inputDeviceDescriptor = device.getDescriptor();
+        if (device != null) {
+            final boolean changed;
+            final String keyboardLayoutDescriptor;
+            synchronized (mDataStore) {
+                try {
+                    changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction);
+                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
+                            inputDeviceDescriptor);
+                } finally {
+                    mDataStore.saveIfNeeded();
+                }
+            }
+
+            if (changed) {
+                if (mSwitchedKeyboardLayoutToast != null) {
+                    mSwitchedKeyboardLayoutToast.cancel();
+                    mSwitchedKeyboardLayoutToast = null;
+                }
+                if (keyboardLayoutDescriptor != null) {
+                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
+                    if (keyboardLayout != null) {
+                        mSwitchedKeyboardLayoutToast = Toast.makeText(
+                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
+                        mSwitchedKeyboardLayoutToast.show();
+                    }
+                }
+
+                reloadKeyboardLayouts();
+            }
         }
     }
 
@@ -976,12 +1205,13 @@
     // Native callback.
     private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
         synchronized (mInputDevicesLock) {
-            mInputDevices = inputDevices;
-
             if (!mInputDevicesChangedPending) {
                 mInputDevicesChangedPending = true;
-                mHandler.sendEmptyMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED);
+                mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
+                        mInputDevices).sendToTarget();
             }
+
+            mInputDevices = inputDevices;
         }
     }
 
@@ -1130,7 +1360,8 @@
             return null;
         }
 
-        String keyboardLayoutDescriptor = getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(
+                inputDeviceDescriptor);
         if (keyboardLayoutDescriptor == null) {
             return null;
         }
@@ -1139,7 +1370,7 @@
         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
             @Override
             public void visitKeyboardLayout(Resources resources,
-                    String descriptor, String label, int keyboardLayoutResId) {
+                    String descriptor, String label, String collection, int keyboardLayoutResId) {
                 try {
                     result[0] = descriptor;
                     result[1] = Streams.readFully(new InputStreamReader(
@@ -1201,7 +1432,19 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
-                    deliverInputDevicesChanged();
+                    deliverInputDevicesChanged((InputDevice[])msg.obj);
+                    break;
+                case MSG_SWITCH_KEYBOARD_LAYOUT:
+                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
+                    break;
+                case MSG_RELOAD_KEYBOARD_LAYOUTS:
+                    reloadKeyboardLayouts();
+                    break;
+                case MSG_UPDATE_KEYBOARD_LAYOUTS:
+                    updateKeyboardLayouts();
+                    break;
+                case MSG_RELOAD_DEVICE_ALIASES:
+                    reloadDeviceAliases();
                     break;
             }
         }
@@ -1262,7 +1505,7 @@
 
     private interface KeyboardLayoutVisitor {
         void visitKeyboardLayout(Resources resources,
-                String descriptor, String label, int keyboardLayoutResId);
+                String descriptor, String label, String collection, int keyboardLayoutResId);
     }
 
     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
@@ -1314,186 +1557,4 @@
             onVibratorTokenDied(this);
         }
     }
-
-    /**
-     * Manages persistent state recorded by the input manager service as an XML file.
-     * Caller must acquire lock on the data store before accessing it.
-     *
-     * File format:
-     * <code>
-     * &lt;input-mananger-state>
-     *   &lt;input-devices>
-     *     &lt;input-device descriptor="xxxxx" keyboard-layout="yyyyy" />
-     *   &gt;input-devices>
-     * &gt;/input-manager-state>
-     * </code>
-     */
-    private static final class PersistentDataStore {
-        // Input device state by descriptor.
-        private final HashMap<String, InputDeviceState> mInputDevices =
-                new HashMap<String, InputDeviceState>();
-        private final AtomicFile mAtomicFile;
-
-        // True if the data has been loaded.
-        private boolean mLoaded;
-
-        // True if there are changes to be saved.
-        private boolean mDirty;
-
-        public PersistentDataStore() {
-            mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"));
-        }
-
-        public void saveIfNeeded() {
-            if (mDirty) {
-                save();
-                mDirty = false;
-            }
-        }
-
-        public String getKeyboardLayout(String inputDeviceDescriptor) {
-            InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
-            return state != null ? state.keyboardLayoutDescriptor : null;
-        }
-
-        public boolean setKeyboardLayout(String inputDeviceDescriptor,
-                String keyboardLayoutDescriptor) {
-            InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
-            if (!Objects.equal(state.keyboardLayoutDescriptor, keyboardLayoutDescriptor)) {
-                state.keyboardLayoutDescriptor = keyboardLayoutDescriptor;
-                setDirty();
-                return true;
-            }
-            return false;
-        }
-
-        private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
-                boolean createIfAbsent) {
-            loadIfNeeded();
-            InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
-            if (state == null && createIfAbsent) {
-                state = new InputDeviceState();
-                mInputDevices.put(inputDeviceDescriptor, state);
-                setDirty();
-            }
-            return state;
-        }
-
-        private void loadIfNeeded() {
-            if (!mLoaded) {
-                load();
-                mLoaded = true;
-            }
-        }
-
-        private void setDirty() {
-            mDirty = true;
-        }
-
-        private void clearState() {
-            mInputDevices.clear();
-        }
-
-        private void load() {
-            clearState();
-
-            final InputStream is;
-            try {
-                is = mAtomicFile.openRead();
-            } catch (FileNotFoundException ex) {
-                return;
-            }
-
-            XmlPullParser parser;
-            try {
-                parser = Xml.newPullParser();
-                parser.setInput(new BufferedInputStream(is), null);
-                loadFromXml(parser);
-            } catch (IOException ex) {
-                Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
-                clearState();
-            } catch (XmlPullParserException ex) {
-                Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
-                clearState();
-            } finally {
-                IoUtils.closeQuietly(is);
-            }
-        }
-
-        private void save() {
-            final FileOutputStream os;
-            try {
-                os = mAtomicFile.startWrite();
-                boolean success = false;
-                try {
-                    XmlSerializer serializer = new FastXmlSerializer();
-                    serializer.setOutput(new BufferedOutputStream(os), "utf-8");
-                    saveToXml(serializer);
-                    serializer.flush();
-                    success = true;
-                } finally {
-                    if (success) {
-                        mAtomicFile.finishWrite(os);
-                    } else {
-                        mAtomicFile.failWrite(os);
-                    }
-                }
-            } catch (IOException ex) {
-                Slog.w(TAG, "Failed to save input manager persistent store data.", ex);
-            }
-        }
-
-        private void loadFromXml(XmlPullParser parser)
-                throws IOException, XmlPullParserException {
-            XmlUtils.beginDocument(parser, "input-manager-state");
-            final int outerDepth = parser.getDepth();
-            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-                if (parser.getName().equals("input-devices")) {
-                    loadInputDevicesFromXml(parser);
-                }
-            }
-        }
-
-        private void loadInputDevicesFromXml(XmlPullParser parser)
-                throws IOException, XmlPullParserException {
-            final int outerDepth = parser.getDepth();
-            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-                if (parser.getName().equals("input-device")) {
-                    String descriptor = parser.getAttributeValue(null, "descriptor");
-                    if (descriptor == null) {
-                        throw new XmlPullParserException(
-                                "Missing descriptor attribute on input-device");
-                    }
-                    InputDeviceState state = new InputDeviceState();
-                    state.keyboardLayoutDescriptor =
-                            parser.getAttributeValue(null, "keyboard-layout");
-                    mInputDevices.put(descriptor, state);
-                }
-            }
-        }
-
-        private void saveToXml(XmlSerializer serializer) throws IOException {
-            serializer.startDocument(null, true);
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-            serializer.startTag(null, "input-manager-state");
-            serializer.startTag(null, "input-devices");
-            for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
-                final String descriptor = entry.getKey();
-                final InputDeviceState state = entry.getValue();
-                serializer.startTag(null, "input-device");
-                serializer.attribute(null, "descriptor", descriptor);
-                if (state.keyboardLayoutDescriptor != null) {
-                    serializer.attribute(null, "keyboard-layout", state.keyboardLayoutDescriptor);
-                }
-                serializer.endTag(null, "input-device");
-            }
-            serializer.endTag(null, "input-devices");
-            serializer.endTag(null, "input-manager-state");
-            serializer.endDocument();
-        }
-    }
-
-    private static final class InputDeviceState {
-        public String keyboardLayoutDescriptor;
-    }
 }
diff --git a/services/java/com/android/server/input/PersistentDataStore.java b/services/java/com/android/server/input/PersistentDataStore.java
new file mode 100644
index 0000000..fbe3e8b
--- /dev/null
+++ b/services/java/com/android/server/input/PersistentDataStore.java
@@ -0,0 +1,416 @@
+/*
+ * 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.server.input;
+
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Slog;
+import android.util.Xml;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+
+/**
+ * Manages persistent state recorded by the input manager service as an XML file.
+ * Caller must acquire lock on the data store before accessing it.
+ *
+ * File format:
+ * <code>
+ * &lt;input-mananger-state>
+ *   &lt;input-devices>
+ *     &lt;input-device descriptor="xxxxx" keyboard-layout="yyyyy" />
+ *   &gt;input-devices>
+ * &gt;/input-manager-state>
+ * </code>
+ */
+final class PersistentDataStore {
+    static final String TAG = "InputManager";
+
+    // Input device state by descriptor.
+    private final HashMap<String, InputDeviceState> mInputDevices =
+            new HashMap<String, InputDeviceState>();
+    private final AtomicFile mAtomicFile;
+
+    // True if the data has been loaded.
+    private boolean mLoaded;
+
+    // True if there are changes to be saved.
+    private boolean mDirty;
+
+    public PersistentDataStore() {
+        mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"));
+    }
+
+    public void saveIfNeeded() {
+        if (mDirty) {
+            save();
+            mDirty = false;
+        }
+    }
+
+    public String getCurrentKeyboardLayout(String inputDeviceDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+        return state != null ? state.getCurrentKeyboardLayout() : null;
+    }
+
+    public boolean setCurrentKeyboardLayout(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+        if (state.setCurrentKeyboardLayout(keyboardLayoutDescriptor)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    public String[] getKeyboardLayouts(String inputDeviceDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+        if (state == null) {
+            return (String[])ArrayUtils.emptyArray(String.class);
+        }
+        return state.getKeyboardLayouts();
+    }
+
+    public boolean addKeyboardLayout(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+        if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean removeKeyboardLayout(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+        if (state.removeKeyboardLayout(keyboardLayoutDescriptor)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+        if (state != null && state.switchKeyboardLayout(direction)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
+        boolean changed = false;
+        for (InputDeviceState state : mInputDevices.values()) {
+            if (state.removeUninstalledKeyboardLayouts(availableKeyboardLayouts)) {
+                changed = true;
+            }
+        }
+        if (changed) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
+            boolean createIfAbsent) {
+        loadIfNeeded();
+        InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
+        if (state == null && createIfAbsent) {
+            state = new InputDeviceState();
+            mInputDevices.put(inputDeviceDescriptor, state);
+            setDirty();
+        }
+        return state;
+    }
+
+    private void loadIfNeeded() {
+        if (!mLoaded) {
+            load();
+            mLoaded = true;
+        }
+    }
+
+    private void setDirty() {
+        mDirty = true;
+    }
+
+    private void clearState() {
+        mInputDevices.clear();
+    }
+
+    private void load() {
+        clearState();
+
+        final InputStream is;
+        try {
+            is = mAtomicFile.openRead();
+        } catch (FileNotFoundException ex) {
+            return;
+        }
+
+        XmlPullParser parser;
+        try {
+            parser = Xml.newPullParser();
+            parser.setInput(new BufferedInputStream(is), null);
+            loadFromXml(parser);
+        } catch (IOException ex) {
+            Slog.w(InputManagerService.TAG, "Failed to load input manager persistent store data.", ex);
+            clearState();
+        } catch (XmlPullParserException ex) {
+            Slog.w(InputManagerService.TAG, "Failed to load input manager persistent store data.", ex);
+            clearState();
+        } finally {
+            IoUtils.closeQuietly(is);
+        }
+    }
+
+    private void save() {
+        final FileOutputStream os;
+        try {
+            os = mAtomicFile.startWrite();
+            boolean success = false;
+            try {
+                XmlSerializer serializer = new FastXmlSerializer();
+                serializer.setOutput(new BufferedOutputStream(os), "utf-8");
+                saveToXml(serializer);
+                serializer.flush();
+                success = true;
+            } finally {
+                if (success) {
+                    mAtomicFile.finishWrite(os);
+                } else {
+                    mAtomicFile.failWrite(os);
+                }
+            }
+        } catch (IOException ex) {
+            Slog.w(InputManagerService.TAG, "Failed to save input manager persistent store data.", ex);
+        }
+    }
+
+    private void loadFromXml(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        XmlUtils.beginDocument(parser, "input-manager-state");
+        final int outerDepth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+            if (parser.getName().equals("input-devices")) {
+                loadInputDevicesFromXml(parser);
+            }
+        }
+    }
+
+    private void loadInputDevicesFromXml(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        final int outerDepth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+            if (parser.getName().equals("input-device")) {
+                String descriptor = parser.getAttributeValue(null, "descriptor");
+                if (descriptor == null) {
+                    throw new XmlPullParserException(
+                            "Missing descriptor attribute on input-device.");
+                }
+                if (mInputDevices.containsKey(descriptor)) {
+                    throw new XmlPullParserException("Found duplicate input device.");
+                }
+
+                InputDeviceState state = new InputDeviceState();
+                state.loadFromXml(parser);
+                mInputDevices.put(descriptor, state);
+            }
+        }
+    }
+
+    private void saveToXml(XmlSerializer serializer) throws IOException {
+        serializer.startDocument(null, true);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        serializer.startTag(null, "input-manager-state");
+        serializer.startTag(null, "input-devices");
+        for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
+            final String descriptor = entry.getKey();
+            final InputDeviceState state = entry.getValue();
+            serializer.startTag(null, "input-device");
+            serializer.attribute(null, "descriptor", descriptor);
+            state.saveToXml(serializer);
+            serializer.endTag(null, "input-device");
+        }
+        serializer.endTag(null, "input-devices");
+        serializer.endTag(null, "input-manager-state");
+        serializer.endDocument();
+    }
+
+    private static final class InputDeviceState {
+        private String mCurrentKeyboardLayout;
+        private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
+
+        public String getCurrentKeyboardLayout() {
+            return mCurrentKeyboardLayout;
+        }
+
+        public boolean setCurrentKeyboardLayout(String keyboardLayout) {
+            if (Objects.equal(mCurrentKeyboardLayout, keyboardLayout)) {
+                return false;
+            }
+            addKeyboardLayout(keyboardLayout);
+            mCurrentKeyboardLayout = keyboardLayout;
+            return true;
+        }
+
+        public String[] getKeyboardLayouts() {
+            if (mKeyboardLayouts.isEmpty()) {
+                return (String[])ArrayUtils.emptyArray(String.class);
+            }
+            return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
+        }
+
+        public boolean addKeyboardLayout(String keyboardLayout) {
+            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
+            if (index >= 0) {
+                return false;
+            }
+            mKeyboardLayouts.add(-index - 1, keyboardLayout);
+            if (mCurrentKeyboardLayout == null) {
+                mCurrentKeyboardLayout = keyboardLayout;
+            }
+            return true;
+        }
+
+        public boolean removeKeyboardLayout(String keyboardLayout) {
+            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
+            if (index < 0) {
+                return false;
+            }
+            mKeyboardLayouts.remove(index);
+            updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
+            return true;
+        }
+
+        private void updateCurrentKeyboardLayoutIfRemoved(
+                String removedKeyboardLayout, int removedIndex) {
+            if (Objects.equal(mCurrentKeyboardLayout, removedKeyboardLayout)) {
+                if (!mKeyboardLayouts.isEmpty()) {
+                    int index = removedIndex;
+                    if (index == mKeyboardLayouts.size()) {
+                        index = 0;
+                    }
+                    mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+                } else {
+                    mCurrentKeyboardLayout = null;
+                }
+            }
+        }
+
+        public boolean switchKeyboardLayout(int direction) {
+            final int size = mKeyboardLayouts.size();
+            if (size < 2) {
+                return false;
+            }
+            int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
+            assert index >= 0;
+            if (direction > 0) {
+                index = (index + 1) % size;
+            } else {
+                index = (index + size - 1) % size;
+            }
+            mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+            return true;
+        }
+
+        public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
+            boolean changed = false;
+            for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
+                String keyboardLayout = mKeyboardLayouts.get(i);
+                if (!availableKeyboardLayouts.contains(keyboardLayout)) {
+                    Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
+                    mKeyboardLayouts.remove(i);
+                    updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+
+        public void loadFromXml(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            final int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if (parser.getName().equals("keyboard-layout")) {
+                    String descriptor = parser.getAttributeValue(null, "descriptor");
+                    if (descriptor == null) {
+                        throw new XmlPullParserException(
+                                "Missing descriptor attribute on keyboard-layout.");
+                    }
+                    String current = parser.getAttributeValue(null, "current");
+                    if (mKeyboardLayouts.contains(descriptor)) {
+                        throw new XmlPullParserException(
+                                "Found duplicate keyboard layout.");
+                    }
+
+                    mKeyboardLayouts.add(descriptor);
+                    if (current != null && current.equals("true")) {
+                        if (mCurrentKeyboardLayout != null) {
+                            throw new XmlPullParserException(
+                                    "Found multiple current keyboard layouts.");
+                        }
+                        mCurrentKeyboardLayout = descriptor;
+                    }
+                }
+            }
+
+            // Maintain invariant that layouts are sorted.
+            Collections.sort(mKeyboardLayouts);
+
+            // Maintain invariant that there is always a current keyboard layout unless
+            // there are none installed.
+            if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
+                mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
+            }
+        }
+
+        public void saveToXml(XmlSerializer serializer) throws IOException {
+            for (String layout : mKeyboardLayouts) {
+                serializer.startTag(null, "keyboard-layout");
+                serializer.attribute(null, "descriptor", layout);
+                if (layout.equals(mCurrentKeyboardLayout)) {
+                    serializer.attribute(null, "current", "true");
+                }
+                serializer.endTag(null, "keyboard-layout");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 1b8c9cb..c82f37c 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -118,7 +118,6 @@
 import android.text.format.Formatter;
 import android.text.format.Time;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -225,6 +224,7 @@
     private static final int MSG_PROCESS_DIED = 4;
     private static final int MSG_LIMIT_REACHED = 5;
     private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
+    private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -1032,14 +1032,7 @@
             }
         }
 
-        try {
-            // make sure stats are recorded frequently enough; we aim for 2MB
-            // threshold for 2GB/month rules.
-            final long persistThreshold = lowestRule / 1000;
-            mNetworkStats.advisePersistThreshold(persistThreshold);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
+        mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
 
         // remove quota on any trailing interfaces
         for (String iface : mMeteredIfaces) {
@@ -1861,6 +1854,19 @@
                         }
                     }
                     mListeners.finishBroadcast();
+                    return true;
+                }
+                case MSG_ADVISE_PERSIST_THRESHOLD: {
+                    final long lowestRule = (Long) msg.obj;
+                    try {
+                        // make sure stats are recorded frequently enough; we aim
+                        // for 2MB threshold for 2GB/month rules.
+                        final long persistThreshold = lowestRule / 1000;
+                        mNetworkStats.advisePersistThreshold(persistThreshold);
+                    } catch (RemoteException e) {
+                        // ignored; service lives in system_server
+                    }
+                    return true;
                 }
                 default: {
                     return false;
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index c2e475a..9ddf011 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -71,7 +71,7 @@
 
     private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
 
-    private long mBucketDuration;
+    private final long mBucketDuration;
 
     private long mStartMillis;
     private long mEndMillis;
@@ -95,6 +95,18 @@
         return mStartMillis;
     }
 
+    /**
+     * Return first atomic bucket in this collection, which is more conservative
+     * than {@link #mStartMillis}.
+     */
+    public long getFirstAtomicBucketMillis() {
+        if (mStartMillis == Long.MAX_VALUE) {
+            return Long.MAX_VALUE;
+        } else {
+            return mStartMillis + mBucketDuration;
+        }
+    }
+
     public long getEndMillis() {
         return mEndMillis;
     }
@@ -121,6 +133,15 @@
      */
     public NetworkStatsHistory getHistory(
             NetworkTemplate template, int uid, int set, int tag, int fields) {
+        return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE);
+    }
+
+    /**
+     * Combine all {@link NetworkStatsHistory} in this collection which match
+     * the requested parameters.
+     */
+    public NetworkStatsHistory getHistory(
+            NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
         final NetworkStatsHistory combined = new NetworkStatsHistory(
                 mBucketDuration, estimateBuckets(), fields);
         for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
@@ -128,7 +149,7 @@
             final boolean setMatches = set == SET_ALL || key.set == set;
             if (key.uid == uid && setMatches && key.tag == tag
                     && templateMatches(template, key.ident)) {
-                combined.recordEntireHistory(entry.getValue());
+                combined.recordHistory(entry.getValue(), start, end);
             }
         }
         return combined;
@@ -145,6 +166,9 @@
         final NetworkStats.Entry entry = new NetworkStats.Entry();
         NetworkStatsHistory.Entry historyEntry = null;
 
+        // shortcut when we know stats will be empty
+        if (start == end) return stats;
+
         for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
             final Key key = mapEntry.getKey();
             if (templateMatches(template, key.ident)) {
@@ -175,8 +199,9 @@
      */
     public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
             long end, NetworkStats.Entry entry) {
-        noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes);
-        findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry);
+        final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag);
+        history.recordData(start, end, entry);
+        noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes);
     }
 
     /**
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 0e93b0a..ba122ec 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -44,6 +44,7 @@
 import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE;
 import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
+import static android.provider.Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV;
 import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED;
 import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE;
 import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
@@ -177,6 +178,7 @@
         public long getPollInterval();
         public long getTimeCacheMaxAge();
         public boolean getSampleEnabled();
+        public boolean getReportXtOverDev();
 
         public static class Config {
             public final long bucketDuration;
@@ -221,6 +223,8 @@
 
     /** Cached {@link #mDevRecorder} stats. */
     private NetworkStatsCollection mDevStatsCached;
+    /** Cached {@link #mXtRecorder} stats. */
+    private NetworkStatsCollection mXtStatsCached;
 
     /** Current counter sets for each UID. */
     private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
@@ -295,6 +299,7 @@
             // read historical network stats from disk, since policy service
             // might need them right away.
             mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
+            mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked();
 
             // bootstrap initial stats to prevent double-counting later
             bootstrapStatsLocked();
@@ -371,6 +376,7 @@
         mUidTagRecorder = null;
 
         mDevStatsCached = null;
+        mXtStatsCached = null;
 
         mSystemReady = false;
     }
@@ -469,12 +475,12 @@
             @Override
             public NetworkStats getSummaryForNetwork(
                     NetworkTemplate template, long start, long end) {
-                return mDevStatsCached.getSummary(template, start, end);
+                return internalGetSummaryForNetwork(template, start, end);
             }
 
             @Override
             public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
-                return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+                return internalGetHistoryForNetwork(template, fields);
             }
 
             @Override
@@ -507,11 +513,56 @@
         };
     }
 
+    /**
+     * Return network summary, splicing between {@link #mDevStatsCached}
+     * and {@link #mXtStatsCached} when appropriate.
+     */
+    private NetworkStats internalGetSummaryForNetwork(
+            NetworkTemplate template, long start, long end) {
+        if (!mSettings.getReportXtOverDev()) {
+            // shortcut when XT reporting disabled
+            return mDevStatsCached.getSummary(template, start, end);
+        }
+
+        // splice stats between DEV and XT, switching over from DEV to XT at
+        // first atomic bucket.
+        final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
+        final NetworkStats dev = mDevStatsCached.getSummary(
+                template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket));
+        final NetworkStats xt = mXtStatsCached.getSummary(
+                template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket));
+
+        xt.combineAllValues(dev);
+        return xt;
+    }
+
+    /**
+     * Return network history, splicing between {@link #mDevStatsCached}
+     * and {@link #mXtStatsCached} when appropriate.
+     */
+    private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
+        if (!mSettings.getReportXtOverDev()) {
+            // shortcut when XT reporting disabled
+            return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+        }
+
+        // splice stats between DEV and XT, switching over from DEV to XT at
+        // first atomic bucket.
+        final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
+        final NetworkStatsHistory dev = mDevStatsCached.getHistory(
+                template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket);
+        final NetworkStatsHistory xt = mXtStatsCached.getHistory(
+                template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE);
+
+        xt.recordEntireHistory(dev);
+        return xt;
+    }
+
     @Override
     public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
         assertBandwidthControlEnabled();
-        return mDevStatsCached.getSummary(template, start, end).getTotalBytes();
+        return internalGetSummaryForNetwork(template, start, end).getTotalBytes();
     }
 
     @Override
@@ -1190,6 +1241,10 @@
             return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
         }
         @Override
+        public boolean getReportXtOverDev() {
+            return getSecureBoolean(NETSTATS_REPORT_XT_OVER_DEV, true);
+        }
+        @Override
         public Config getDevConfig() {
             return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
                     getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 497ee4b..88f5ec5 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -240,6 +240,9 @@
     // This is where all application persistent data goes for secondary users.
     final File mUserAppDataDir;
 
+    /** The location for ASEC container files on internal storage. */
+    final String mAsecInternalPath;
+
     // This is the object monitoring the framework dir.
     final FileObserver mFrameworkInstallObserver;
 
@@ -520,7 +523,6 @@
                         // Something seriously wrong. Bail out
                         Slog.e(TAG, "Cannot bind to media container service");
                         for (HandlerParams params : mPendingInstalls) {
-                            mPendingInstalls.remove(0);
                             // Indicate service bind error
                             params.serviceError();
                         }
@@ -572,7 +574,6 @@
                         if (!connectToService()) {
                             Slog.e(TAG, "Failed to bind to media container service");
                             for (HandlerParams params : mPendingInstalls) {
-                                mPendingInstalls.remove(0);
                                 // Indicate service bind error
                                 params.serviceError();
                             }
@@ -907,6 +908,7 @@
 
             File dataDir = Environment.getDataDirectory();
             mAppDataDir = new File(dataDir, "data");
+            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
@@ -1043,7 +1045,7 @@
             scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanMode | SCAN_NO_DEX, 0);
-            
+
             // Collect all system packages.
             mSystemAppDir = new File(Environment.getRootDirectory(), "app");
             mSystemInstallObserver = new AppDirObserver(
@@ -1064,7 +1066,7 @@
             mInstaller.moveFiles();
 
             // Prune any system packages that no longer exist.
-            final List<String> possiblyDeletedSystemApps = new ArrayList<String>();
+            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
             if (!mOnlyCore) {
                 Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                 while (psit.hasNext()) {
@@ -1104,7 +1106,10 @@
                         mInstaller.remove(ps.name, 0);
                         sUserManager.removePackageForAllUsers(ps.name);
                     } else {
-                        possiblyDeletedSystemApps.add(ps.name);
+                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
+                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
+                            possiblyDeletedUpdatedSystemApps.add(ps.name);
+                        }
                     }
                 }
             }
@@ -1135,18 +1140,33 @@
                         scanMode, 0);
 
                 /**
-                 * Remove disable package settings for any system apps
-                 * that were removed via an OTA.
+                 * Remove disable package settings for any updated system
+                 * apps that were removed via an OTA. If they're not a
+                 * previously-updated app, remove them completely.
+                 * Otherwise, just revoke their system-level permissions.
                  */
-                for (String deletedAppName : possiblyDeletedSystemApps) {
+                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                     PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
-                    if (deletedPkg != null) {
-                        mSettings.removeDisabledSystemPackageLPw(deletedAppName);
+                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);
+
+                    String msg;
+                    if (deletedPkg == null) {
+                        msg = "Updated system package " + deletedAppName
+                                + " no longer exists; wiping its data";
+
+                        mInstaller.remove(deletedAppName, 0);
+                        sUserManager.removePackageForAllUsers(deletedAppName);
+                    } else {
+                        msg = "Updated system app + " + deletedAppName
+                                + " no longer present; removing system privileges for "
+                                + deletedAppName;
+
                         deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
 
                         PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                         deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                     }
+                    reportSettingsProblem(Log.WARN, msg);
                 }
             } else {
                 mAppInstallObserver = null;
@@ -6461,6 +6481,11 @@
         }
     }
 
+    private boolean isAsecExternal(String cid) {
+        final String asecPath = PackageHelper.getSdFilesystem(cid);
+        return !asecPath.startsWith(mAsecInternalPath);
+    }
+
     /**
      * Extract the MountService "container ID" from the full code path of an
      * .apk.
@@ -6499,7 +6524,7 @@
         }
 
         AsecInstallArgs(String cid) {
-            super(null, null, 0, null, null);
+            super(null, null, isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0, null, null);
             this.cid = cid;
             setCachePath(PackageHelper.getSdDir(cid));
         }
@@ -8641,6 +8666,14 @@
         });
     }
 
+    /**
+     * Called by MountService when the initial ASECs to scan are available.
+     * Should block until all the ASEC containers are finished being scanned.
+     */
+    public void scanAvailableAsecs() {
+        updateExternalMediaStatusInner(true, false);
+    }
+
     /*
      * Collect information of applications on external media, map them against
      * existing containers and update information based on current mount status.
@@ -8775,7 +8808,11 @@
                     continue;
                 }
                 // Parse package
-                int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+                int parseFlags = mDefParseFlags;
+                if (args.isExternal()) {
+                    parseFlags |= PackageParser.PARSE_ON_SDCARD;
+                }
+
                 doGc = true;
                 synchronized (mInstallLock) {
                     final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 480992b..d6954a5 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -134,10 +134,11 @@
     }
 
     private void updateWindowsAppsAndRotationAnimationsLocked() {
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
         int i;
-        final int NAT = mService.mAppTokens.size();
+        final int NAT = appTokens.size();
         for (i=0; i<NAT; i++) {
-            final AppWindowAnimator appAnimator = mService.mAppTokens.get(i).mAppAnimator;
+            final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
@@ -269,9 +270,19 @@
                                 mPendingLayoutChanges);
                         }
                         mService.mFocusMayChange = true;
-                    } else if (win.isReadyForDisplay()) {
+                    }
+                    if (win.isReadyForDisplay()) {
                         mForceHiding = true;
                     }
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "Force hide " + mForceHiding
+                            + " hasSurface=" + win.mHasSurface
+                            + " policyVis=" + win.mPolicyVisibility
+                            + " destroying=" + win.mDestroying
+                            + " attHidden=" + win.mAttachedHidden
+                            + " vis=" + win.mViewVisibility
+                            + " hidden=" + win.mRootToken.hidden
+                            + " anim=" + win.mWinAnimator.mAnimation);
                 } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
                     final boolean changed;
                     if (mForceHiding) {
@@ -391,9 +402,10 @@
     private void testTokenMayBeDrawnLocked() {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final int NT = mService.mAppTokens.size();
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final int NT = appTokens.size();
         for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = mService.mAppTokens.get(i);
+            AppWindowToken wtoken = appTokens.get(i);
             if (wtoken.mAppAnimator.freezingScreen) {
                 int numInteresting = wtoken.numInterestingWindows;
                 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
@@ -538,8 +550,16 @@
         if (mDimAnimator == null) {
             mDimAnimator = new DimAnimator(mService.mFxSession);
         }
-        mService.mH.sendMessage(mService.mH.obtainMessage(SET_DIM_PARAMETERS,
-                new DimAnimator.Parameters(winAnimator, width, height, target)));
+        // Only set dim params on the highest dimmed layer.
+        final WindowStateAnimator dimWinAnimator = mDimParams == null
+                ? null : mDimParams.mDimWinAnimator;
+        // Don't turn on for an unshown surface, or for any layer but the highest dimmed one.
+        if (winAnimator.mSurfaceShown &&
+                (dimWinAnimator == null || !dimWinAnimator.mSurfaceShown
+                || dimWinAnimator.mAnimLayer < winAnimator.mAnimLayer)) {
+            mService.mH.sendMessage(mService.mH.obtainMessage(SET_DIM_PARAMETERS,
+                    new DimAnimator.Parameters(winAnimator, width, height, target)));
+        }
     }
 
     // TODO(cmautner): Move into Handler
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b3ac6f1..b1612a1 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -351,13 +351,20 @@
     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
 
     /**
-     * Z-ordered (bottom-most first) list of all application tokens, for
-     * controlling the ordering of windows in different applications.  This
-     * contains AppWindowToken objects.
+     * List controlling the ordering of windows in different applications which must
+     * be kept in sync with ActivityManager.
      */
     final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
 
     /**
+     * AppWindowTokens in the Z order they were in at the start of an animation. Between
+     * animations this list is maintained in the exact order of mAppTokens. If tokens
+     * are added to mAppTokens during an animation an attempt is made to insert them at the same
+     * logical location in this list. Note that this list is always in sync with mWindows.
+     */
+    ArrayList<AppWindowToken> mAnimatingAppTokens = new ArrayList<AppWindowToken>();
+
+    /**
      * Application tokens that are in the process of exiting, but still
      * on screen for animations.
      */
@@ -529,11 +536,11 @@
     boolean mSkipAppTransitionAnimation = false;
     final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
     final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
-    final ArrayList<AppWindowToken> mToTopApps = new ArrayList<AppWindowToken>();
-    final ArrayList<AppWindowToken> mToBottomApps = new ArrayList<AppWindowToken>();
 
     Display mDisplay;
 
+    boolean mIsTouchDevice;
+
     final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
@@ -1008,10 +1015,10 @@
                         + client.asBinder() + " (token=" + token + ")");
                     // Figure out where the window should go, based on the
                     // order of applications.
-                    final int NA = mAppTokens.size();
+                    final int NA = mAnimatingAppTokens.size();
                     WindowState pos = null;
                     for (i=NA-1; i>=0; i--) {
-                        AppWindowToken t = mAppTokens.get(i);
+                        AppWindowToken t = mAnimatingAppTokens.get(i);
                         if (t == token) {
                             i--;
                             break;
@@ -1044,7 +1051,7 @@
                         // Continue looking down until we find the first
                         // token that has windows.
                         while (i >= 0) {
-                            AppWindowToken t = mAppTokens.get(i);
+                            AppWindowToken t = mAnimatingAppTokens.get(i);
                             final int NW = t.windows.size();
                             if (NW > 0) {
                                 pos = t.windows.get(NW-1);
@@ -1165,6 +1172,7 @@
         }
     }
 
+    /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
     static boolean canBeImeTarget(WindowState w) {
         final int fl = w.mAttrs.flags
                 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
@@ -1173,10 +1181,11 @@
             if (DEBUG_INPUT_METHOD) {
                 Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
                 if (!w.isVisibleOrAdding()) {
-                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface + " reportDestroy="
-                            + w.mWinAnimator.mReportDestroySurface
+                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface
                             + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
-                            + " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden
+                            + " policyVis=" + w.mPolicyVisibility
+                            + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
+                            + " attachHid=" + w.mAttachedHidden
                             + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
                     if (w.mAppToken != null) {
                         Slog.i(TAG, "  mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
@@ -1633,7 +1642,7 @@
                     continue;
                 }
             }
-            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": readyfordisplay="
+            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": readyfordisplay="
                     + w.isReadyForDisplay() + " mDrawState=" + w.mWinAnimator.mDrawState);
             if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
                     && (mWallpaperTarget == w || w.isDrawnLw())) {
@@ -1726,12 +1735,15 @@
                                 Slog.v(TAG, "Old wallpaper still the target.");
                             }
                             mWallpaperTarget = oldW;
-                        }
-
+                            foundW = oldW;
+                            foundI = oldI;
+                            mLowerWallpaperTarget = null;
+                            mUpperWallpaperTarget = null;
+                        } 
                         // Now set the upper and lower wallpaper targets
                         // correctly, and make sure that we are positioning
                         // the wallpaper below the lower.
-                        if (foundI > oldI) {
+                        else if (foundI > oldI) {
                             // The new target is on top of the old one.
                             if (DEBUG_WALLPAPER) {
                                 Slog.v(TAG, "Found target above old target.");
@@ -1869,7 +1881,7 @@
                 }
 
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
-                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "adjustWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
 
                 // First, if this window is at the current index, then all
@@ -1923,7 +1935,7 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
-                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
             }
         }
@@ -2651,7 +2663,7 @@
             int requestedHeight, int viewVisibility, int flags,
             Rect outFrame, Rect outContentInsets,
             Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
-        boolean displayed = false;
+        boolean toBeDisplayed = false;
         boolean inTouchMode;
         boolean configChanged;
         boolean surfaceChanged = false;
@@ -2754,7 +2766,7 @@
             }
             if (viewVisibility == View.VISIBLE &&
                     (win.mAppToken == null || !win.mAppToken.clientHidden)) {
-                displayed = !win.isVisibleLw();
+                toBeDisplayed = !win.isVisibleLw();
                 if (win.mExiting) {
                     winAnimator.cancelExitAnimationForNextAnimationLocked();
                     win.mExiting = false;
@@ -2766,7 +2778,7 @@
                 if (oldVisibility == View.GONE) {
                     winAnimator.mEnterAnimationPending = true;
                 }
-                if (displayed) {
+                if (toBeDisplayed) {
                     if (win.isDrawnLw() && okToDisplay()) {
                         winAnimator.applyEnterAnimationLocked();
                     }
@@ -2792,7 +2804,7 @@
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
                     // To change the format, we need to re-build the surface.
                     winAnimator.destroySurfaceLocked();
-                    displayed = true;
+                    toBeDisplayed = true;
                     surfaceChanged = true;
                 }
                 try {
@@ -2802,8 +2814,6 @@
                     Surface surface = winAnimator.createSurfaceLocked();
                     if (surface != null) {
                         outSurface.copyFrom(surface);
-                        winAnimator.mReportDestroySurface = false;
-                        winAnimator.mSurfacePendingDestroy = false;
                         if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                 "  OUT SURFACE " + outSurface + ": copied");
                     } else {
@@ -2820,7 +2830,7 @@
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
-                if (displayed) {
+                if (toBeDisplayed) {
                     focusMayChange = true;
                 }
                 if (win.mAttrs.type == TYPE_INPUT_METHOD
@@ -2845,11 +2855,10 @@
                 winAnimator.mEnterAnimationPending = false;
                 if (winAnimator.mSurface != null) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
-                            + ": mExiting=" + win.mExiting
-                            + " mSurfacePendingDestroy=" + winAnimator.mSurfacePendingDestroy);
+                            + ": mExiting=" + win.mExiting);
                     // If we are not currently running the exit animation, we
                     // need to see about starting one.
-                    if (!win.mExiting || winAnimator.mSurfacePendingDestroy) {
+                    if (!win.mExiting) {
                         surfaceChanged = true;
                         // Try starting an animation; if there isn't one, we
                         // can destroy the surface right away.
@@ -2857,7 +2866,7 @@
                         if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
                             transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                         }
-                        if (!winAnimator.mSurfacePendingDestroy && win.isWinVisibleLw() &&
+                        if (win.isWinVisibleLw() &&
                                 winAnimator.applyAnimationLocked(transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
@@ -2880,22 +2889,8 @@
                     }
                 }
 
-                if (winAnimator.mSurface == null || (win.getAttrs().flags
-                        & WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0
-                        || winAnimator.mSurfacePendingDestroy) {
-                    // We could be called from a local process, which
-                    // means outSurface holds its current surface.  Ensure the
-                    // surface object is cleared, but we don't necessarily want
-                    // it actually destroyed at this point.
-                    winAnimator.mSurfacePendingDestroy = false;
-                    outSurface.release();
-                    if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
-                } else if (winAnimator.mSurface != null) {
-                    if (DEBUG_VISIBILITY) Slog.i(TAG,
-                            "Keeping surface, will report destroy: " + win);
-                    winAnimator.mReportDestroySurface = true;
-                    outSurface.copyFrom(winAnimator.mSurface);
-                }
+                outSurface.release();
+                if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
             }
 
             if (focusMayChange) {
@@ -2912,7 +2907,7 @@
             boolean assignLayers = false;
 
             if (imMayMove) {
-                if (moveInputMethodWindowsIfNeededLocked(false) || displayed) {
+                if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) {
                     // Little hack here -- we -should- be able to rely on the
                     // function to return true if the IME has moved and needs
                     // its layer recomputed.  However, if the IME was hidden
@@ -2934,7 +2929,7 @@
             }
             configChanged = updateOrientationFromAppTokensLocked(false);
             performLayoutAndPlaceSurfacesLocked();
-            if (displayed && win.mIsWallpaper) {
+            if (toBeDisplayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mAppDisplayWidth, mAppDisplayHeight, false);
             }
             if (win.mAppToken != null) {
@@ -2970,7 +2965,7 @@
         Binder.restoreCallingIdentity(origId);
 
         return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
-                | (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
+                | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
                 | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)
                 | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);
     }
@@ -3498,6 +3493,25 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    /**
+     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
+     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
+     * @param addPos The location the token was inserted into in mAppTokens.
+     * @param wtoken The token to insert.
+     */
+    private void addAppTokenToAnimating(final int addPos, final AppWindowToken wtoken) {
+        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
+            // It was inserted into the beginning or end of mAppTokens. Honor that.
+            mAnimatingAppTokens.add(addPos, wtoken);
+            return;
+        }
+        // Find the item immediately above the mAppTokens insertion point and put the token
+        // immediately below that one in mAnimatingAppTokens.
+        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
+        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
+    }
+
+    @Override
     public void addAppToken(int addPos, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3532,6 +3546,7 @@
             wtoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + wtoken);
             mAppTokens.add(addPos, wtoken);
+            addAppTokenToAnimating(addPos, wtoken);
             mTokenMap.put(token.asBinder(), wtoken);
 
             // Application tokens start out hidden.
@@ -3849,7 +3864,7 @@
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                     TAG, "Prepare app transition: transit=" + transit
                     + " mNextAppTransition=" + mNextAppTransition
-                    + "\nCallers=" + Debug.getCallers(3));
+                    + " Callers=" + Debug.getCallers(3));
             if (okToDisplay()) {
                 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
                         || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
@@ -4481,6 +4496,7 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
                 mAppTokens.remove(wtoken);
+                mAnimatingAppTokens.remove(wtoken);
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4512,11 +4528,13 @@
 
     private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
         final int NW = token.windows.size();
+        if (NW > 0) {
+            mWindowsChanged = true;
+        }
         for (int i=0; i<NW; i++) {
             WindowState win = token.windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
-            mWindowsChanged = true;
             int j = win.mChildWindows.size();
             while (j > 0) {
                 j--;
@@ -4535,6 +4553,12 @@
         }
     }
 
+    void dumpAnimatingAppTokensLocked() {
+        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
+            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
+        }
+    }
+
     void dumpWindowsLocked() {
         for (int i=mWindows.size()-1; i>=0; i--) {
             Slog.v(TAG, "  #" + i + ": " + mWindows.get(i));
@@ -4544,7 +4568,7 @@
     private int findWindowOffsetLocked(int tokenPos) {
         final int NW = mWindows.size();
 
-        if (tokenPos >= mAppTokens.size()) {
+        if (tokenPos >= mAnimatingAppTokens.size()) {
             int i = NW;
             while (i > 0) {
                 i--;
@@ -4558,7 +4582,7 @@
         while (tokenPos > 0) {
             // Find the first app token below the new position that has
             // a window displayed.
-            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
+            final AppWindowToken wtoken = mAnimatingAppTokens.get(tokenPos-1);
             if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
                     + tokenPos + " -- " + wtoken.token);
             if (wtoken.sendingToBottom) {
@@ -4646,9 +4670,16 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
             if (DEBUG_REORDER) dumpAppTokensLocked();
             final AppWindowToken wtoken = findAppWindowToken(token);
+            final int oldIndex = mAppTokens.indexOf(wtoken);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
                     "Start moving token " + wtoken + " initially at "
-                    + mAppTokens.indexOf(wtoken));
+                    + oldIndex);
+            if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
+                        && !mAppTransitionRunning) {
+                // animation towards back has not started, copy old list for duration of animation.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
+            }
             if (wtoken == null || !mAppTokens.remove(wtoken)) {
                 Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
                       + token + " (" + wtoken + ")");
@@ -4658,24 +4689,30 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
             else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
             if (DEBUG_REORDER) dumpAppTokensLocked();
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) {
+                // Not animating, bring animating app list in line with mAppTokens.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
 
-            final long origId = Binder.clearCallingIdentity();
-            if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
-            if (DEBUG_REORDER) dumpWindowsLocked();
-            if (tmpRemoveAppWindowsLocked(wtoken)) {
-                if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
+                // Bring window ordering, window focus and input window in line with new app token
+                final long origId = Binder.clearCallingIdentity();
+                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
                 if (DEBUG_REORDER) dumpWindowsLocked();
-                reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
-                if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
-                if (DEBUG_REORDER) dumpWindowsLocked();
-                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                        false /*updateInputWindows*/);
-                mLayoutNeeded = true;
-                mInputMonitor.setUpdateInputWindowsNeededLw();
-                performLayoutAndPlaceSurfacesLocked();
-                mInputMonitor.updateInputWindowsLw(false /*force*/);
+                if (tmpRemoveAppWindowsLocked(wtoken)) {
+                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
+                    if (DEBUG_REORDER) dumpWindowsLocked();
+                    reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
+                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
+                    if (DEBUG_REORDER) dumpWindowsLocked();
+                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+                            false /*updateInputWindows*/);
+                    mLayoutNeeded = true;
+                    mInputMonitor.setUpdateInputWindowsNeededLw();
+                    performLayoutAndPlaceSurfacesLocked();
+                    mInputMonitor.updateInputWindowsLw(false /*force*/);
+                }
+                Binder.restoreCallingIdentity(origId);
             }
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -4716,7 +4753,9 @@
                 assignLayersLocked();
             }
             mLayoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            if (!mInLayout) {
+                performLayoutAndPlaceSurfacesLocked();
+            }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
     }
@@ -4772,22 +4811,22 @@
                             "Adding next to top: " + wt);
                     mAppTokens.add(wt);
                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-                        mToTopApps.remove(wt);
-                        mToBottomApps.remove(wt);
-                        mToTopApps.add(wt);
                         wt.sendingToBottom = false;
-                        wt.sendingToTop = true;
                     }
                 }
             }
 
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
                 moveAppWindowsLocked(tokens, mAppTokens.size());
             }
         }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public void moveAppTokensToBottom(List<IBinder> tokens) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "moveAppTokensToBottom()")) {
@@ -4796,8 +4835,14 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
-            removeAppTokensLocked(tokens);
             final int N = tokens.size();
+            if (N > 0 && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                // animating towards back, hang onto old list for duration of animation.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
+            }
+            removeAppTokensLocked(tokens);
             int pos = 0;
             for (int i=0; i<N; i++) {
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
@@ -4806,17 +4851,16 @@
                             "Adding next to bottom: " + wt + " at " + pos);
                     mAppTokens.add(pos, wt);
                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-                        mToTopApps.remove(wt);
-                        mToBottomApps.remove(wt);
-                        mToBottomApps.add(i, wt);
-                        wt.sendingToTop = false;
                         wt.sendingToBottom = true;
                     }
                     pos++;
                 }
             }
 
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
                 moveAppWindowsLocked(tokens, 0);
             }
         }
@@ -5023,6 +5067,12 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
+    public void switchKeyboardLayout(int deviceId, int direction) {
+        mInputManager.switchKeyboardLayout(deviceId, direction);
+    }
+
+    // Called by window manager policy.  Not exposed externally.
+    @Override
     public void shutdown() {
         ShutdownThread.shutdown(mContext, true);
     }
@@ -5256,9 +5306,14 @@
 
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
+    @Override
     public void showStrictModeViolation(boolean on) {
         if (mHeadless) return;
+        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, 0));
+    }
 
+    private void showStrictModeViolation(int arg) {
+        final boolean on = arg != 0;
         int pid = Binder.getCallingPid();
         synchronized(mWindowMap) {
             // Ignoring requests to enable the red border from clients
@@ -6391,8 +6446,12 @@
                             WindowManagerPolicy.PRESENCE_EXTERNAL :
                                     WindowManagerPolicy.PRESENCE_INTERNAL;
 
-                    if ((sources & InputDevice.SOURCE_TOUCHSCREEN) != 0) {
-                        config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
+                    if (mIsTouchDevice) {
+                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) != 0) {
+                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
+                        }
+                    } else {
+                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
                     }
 
                     if ((sources & InputDevice.SOURCE_TRACKBALL) != 0) {
@@ -6562,15 +6621,24 @@
 
     public void setEventDispatching(boolean enabled) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "resumeKeyDispatching()")) {
+                "setEventDispatching()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
 
         synchronized (mWindowMap) {
             mInputMonitor.setEventDispatchingLw(enabled);
+            sendScreenStatusToClientsLocked();
         }
+    }
 
-        sendScreenStatusToClients();
+    public IBinder getFocusedWindowClientToken() {
+        synchronized (mWindowMap) {
+            WindowState windowState = getFocusedWindowLocked();
+            if (windowState != null) {
+                return windowState.mClient.asBinder();
+            }
+            return null;
+        }
     }
 
     private WindowState getFocusedWindow() {
@@ -6626,6 +6694,8 @@
             }
             WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
             mDisplay = wm.getDefaultDisplay();
+            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_TOUCHSCREEN);
             synchronized(mDisplaySizeLock) {
                 mInitialDisplayWidth = mDisplay.getRawWidth();
                 mInitialDisplayHeight = mDisplay.getRawHeight();
@@ -6664,7 +6734,7 @@
         mPolicy.systemReady();
     }
 
-    private void sendScreenStatusToClients() {
+    private void sendScreenStatusToClientsLocked() {
         final ArrayList<WindowState> windows = mWindows;
         final int count = windows.size();
         boolean on = mPowerManager.isScreenOn();
@@ -6706,6 +6776,7 @@
         public static final int BOOT_TIMEOUT = 23;
         public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
         public static final int BULK_UPDATE_PARAMETERS = 25;
+        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
@@ -6996,6 +7067,8 @@
                                     "*** APP TRANSITION TIMEOUT");
                             mAppTransitionReady = true;
                             mAppTransitionTimeout = true;
+                            mAnimatingAppTokens.clear();
+                            mAnimatingAppTokens.addAll(mAppTokens);
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -7171,6 +7244,11 @@
                     break;
                 }
 
+                case SHOW_STRICT_MODE_VIOLATION: {
+                    showStrictModeViolation(msg.arg1);
+                    break;
+                }
+
                 // Animation messages. Move to Window{State}Animator
                 case SET_TRANSPARENT_REGION: {
                     Pair<WindowStateAnimator, Region> pair =
@@ -7228,9 +7306,11 @@
             WindowState imFocus;
             if (idx > 0) {
                 imFocus = mWindows.get(idx-1);
-                //Log.i(TAG, "Desired input method target: " + imFocus);
-                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
-                //Log.i(TAG, "Last focus: " + this.mLastFocus);
+                if (DEBUG_INPUT_METHOD) {
+                    Slog.i(TAG, "Desired input method target: " + imFocus);
+                    Slog.i(TAG, "Current focus: " + this.mCurrentFocus);
+                    Slog.i(TAG, "Last focus: " + this.mLastFocus);
+                }
                 if (imFocus != null) {
                     // This may be a starting window, in which case we still want
                     // to count it as okay.
@@ -7241,17 +7321,20 @@
                         for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
                             WindowState w = imFocus.mAppToken.windows.get(i);
                             if (w != imFocus) {
-                                //Log.i(TAG, "Switching to real app window: " + w);
+                                Log.i(TAG, "Switching to real app window: " + w);
                                 imFocus = w;
                                 break;
                             }
                         }
                     }
-                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
-                    //if (imFocus.mSession.mClient != null) {
-                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
-                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
-                    //}
+                    if (DEBUG_INPUT_METHOD) {
+                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
+                        if (imFocus.mSession.mClient != null) {
+                            Slog.i(TAG, "IM target client binder: "
+                                    + imFocus.mSession.mClient.asBinder());
+                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
+                        }
+                    }
                     if (imFocus.mSession.mClient != null &&
                             imFocus.mSession.mClient.asBinder() == client.asBinder()) {
                         return true;
@@ -7509,9 +7592,9 @@
         }
 
         // And add in the still active app tokens in Z order.
-        NT = mAppTokens.size();
+        NT = mAnimatingAppTokens.size();
         for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
+            i = reAddAppWindowsLocked(i, mAnimatingAppTokens.get(j));
         }
 
         i -= lastWallpaper;
@@ -7531,7 +7614,7 @@
                 }
             }
             Slog.w(TAG, "Current app token list:");
-            dumpAppTokensLocked();
+            dumpAnimatingAppTokensLocked();
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
@@ -7600,7 +7683,8 @@
             if (DEBUG) {
                 throw new RuntimeException("Recursive call!");
             }
-            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
+            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+                    + Debug.getCallers(3));
             return;
         }
 
@@ -7889,22 +7973,7 @@
 
             mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
 
-            // If there are applications waiting to come to the
-            // top of the stack, now is the time to move their windows.
-            // (Note that we don't do apps going to the bottom
-            // here -- we want to keep their windows in the old
-            // Z-order until the animation completes.)
-            if (mToTopApps.size() > 0) {
-                NN = mAppTokens.size();
-                for (i=0; i<NN; i++) {
-                    AppWindowToken wtoken = mAppTokens.get(i);
-                    if (wtoken.sendingToTop) {
-                        wtoken.sendingToTop = false;
-                        moveAppWindowsLocked(wtoken, NN, false);
-                    }
-                }
-                mToTopApps.clear();
-            }
+            rebuildAppWindowListLocked();
 
             // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
             WindowState oldWallpaper =
@@ -8131,13 +8200,14 @@
         int changes = 0;
 
         mAppTransitionRunning = false;
-        // Clear information about apps that were moving.
-        mToBottomApps.clear();
-
+        // Restore window app tokens to the ActivityManager views
+        mAnimatingAppTokens.clear();
+        mAnimatingAppTokens.addAll(mAppTokens);
         rebuildAppWindowListLocked();
+
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
         mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
-        moveInputMethodWindowsIfNeededLocked(false);
+        moveInputMethodWindowsIfNeededLocked(true);
         mInnerFields.mWallpaperMayChange = true;
         // Since the window list has been rebuilt, focus might
         // have to be recomputed since the actual order of windows
@@ -8218,7 +8288,7 @@
                 // to go through the process of getting informed
                 // by the application when it has finished drawing.
                 if (w.mOrientationChanging) {
-                    if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
+                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
                             + w + ", surface " + winAnimator.mSurface);
                     winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
@@ -8659,25 +8729,11 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "performLayout: App token exiting now removed" + token);
                 mAppTokens.remove(token);
+                mAnimatingAppTokens.remove(token);
                 mExitingAppTokens.remove(i);
             }
         }
 
-        if (!mAnimator.mAnimating && mAppTransitionRunning) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            mAppTransitionRunning = false;
-            mLayoutNeeded = true;
-            rebuildAppWindowListLocked();
-            assignLayersLocked();
-            // Clear information about apps that were moving.
-            mToBottomApps.clear();
-        }
-
         if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
             for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
                 try {
@@ -9006,7 +9062,7 @@
             AppWindowToken thisApp = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
-            if (thisApp != null && thisApp.removed) {
+            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
                 continue;
             }
 
@@ -9409,6 +9465,21 @@
                 }
             }
         }
+        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
+            pw.println();
+            pw.println("  Application tokens during animation:");
+            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mAnimatingAppTokens.get(i);
+                pw.print("  App moving to bottom #"); pw.print(i);
+                        pw.print(' '); pw.print(token);
+                if (dumpAll) {
+                    pw.println(':');
+                    token.dump(pw, "    ");
+                } else {
+                    pw.println();
+                }
+            }
+        }
         pw.println();
         if (mOpeningApps.size() > 0) {
             pw.print("  mOpeningApps="); pw.println(mOpeningApps);
@@ -9416,12 +9487,6 @@
         if (mClosingApps.size() > 0) {
             pw.print("  mClosingApps="); pw.println(mClosingApps);
         }
-        if (mToTopApps.size() > 0) {
-            pw.print("  mToTopApps="); pw.println(mToTopApps);
-        }
-        if (mToBottomApps.size() > 0) {
-            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
-        }
     }
 
     void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1fd80c2..8f2ef76 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -679,8 +679,7 @@
      */
     boolean isVisibleOrAdding() {
         final AppWindowToken atoken = mAppToken;
-        return ((mHasSurface && !mWinAnimator.mReportDestroySurface)
-                        || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
+        return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                 && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested)
                 && !mExiting && !mDestroying;
@@ -842,7 +841,9 @@
         }
     }
 
-    /** Returns true if this window desires key events. */
+    /** Returns true if this window desires key events.
+     * TODO(cmautner): Is this the same as {@link WindowManagerService#canBeImeTarget}
+     */
     public final boolean canReceiveKeys() {
         return     isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE)
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 5516dea..affe5d49 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -71,8 +71,6 @@
 
     Surface mSurface;
     Surface mPendingDestroySurface;
-    boolean mReportDestroySurface;
-    boolean mSurfacePendingDestroy;
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -405,8 +403,8 @@
 
     boolean finishDrawingLocked() {
         if (mDrawState == DRAW_PENDING) {
-            if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(
-                TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
+            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
+                Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
                         + mSurface);
             mDrawState = COMMIT_DRAW_PENDING;
             return true;
@@ -419,7 +417,7 @@
         if (mDrawState != COMMIT_DRAW_PENDING) {
             return false;
         }
-        if (DEBUG_ANIM)
+        if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
             Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurface);
         mDrawState = READY_TO_SHOW;
         final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING;
@@ -506,7 +504,9 @@
         @Override
         public void setWindowCrop(Rect crop) {
             super.setWindowCrop(crop);
-            mWindowCrop.set(crop);
+            if (crop != null) {
+                mWindowCrop.set(crop);
+            }
             Slog.v(SURFACE_TAG, "setWindowCrop: " + this + ". Called by "
                     + Debug.getCallers(3));
         }
@@ -561,8 +561,6 @@
 
     Surface createSurfaceLocked() {
         if (mSurface == null) {
-            mReportDestroySurface = false;
-            mSurfacePendingDestroy = false;
             if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": mDrawState=DRAW_PENDING");
             mDrawState = DRAW_PENDING;
@@ -694,7 +692,6 @@
             mWin.mAppToken.startingDisplayed = false;
         }
 
-        mDrawState = NO_SURFACE;
         if (mSurface != null) {
 
             int i = mWin.mChildWindows.size();
@@ -704,17 +701,6 @@
                 c.mAttachedHidden = true;
             }
 
-            if (mReportDestroySurface) {
-                mReportDestroySurface = false;
-                mSurfacePendingDestroy = true;
-                try {
-                    mWin.mClient.dispatchGetNewSurface();
-                    // We'll really destroy on the next time around.
-                    return;
-                } catch (RemoteException e) {
-                }
-            }
-
             try {
                 if (DEBUG_VISIBILITY) {
                     RuntimeException e = null;
@@ -760,6 +746,7 @@
             mSurfaceShown = false;
             mSurface = null;
             mWin.mHasSurface =false;
+            mDrawState = NO_SURFACE;
         }
     }
 
@@ -1147,7 +1134,7 @@
             }
         } else {
             if (DEBUG_ANIM) {
-                Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
+                // Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
             }
             displayed = true;
         }
@@ -1247,7 +1234,8 @@
 
             // Force the show in the next prepareSurfaceLocked() call.
             mLastAlpha = -1;
-            if (DEBUG_ANIM) Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN");
+            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
+                Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + this);
             mDrawState = HAS_DRAWN;
             mService.scheduleAnimationLocked();
 
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java
index 3cd256e..5ec151b 100644
--- a/services/java/com/android/server/wm/WindowToken.java
+++ b/services/java/com/android/server/wm/WindowToken.java
@@ -71,10 +71,6 @@
     // windows will be put to the bottom of the list.
     boolean sendingToBottom;
 
-    // Set to true when this token is in a pending transaction where its
-    // windows will be put to the top of the list.
-    boolean sendingToTop;
-
     WindowToken(WindowManagerService _service, IBinder _token, int type, boolean _explicit) {
         service = _service;
         token = _token;
@@ -88,11 +84,10 @@
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
                 pw.print(" hidden="); pw.print(hidden);
                 pw.print(" hasVisible="); pw.println(hasVisible);
-        if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) {
+        if (waitingToShow || waitingToHide || sendingToBottom) {
             pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
                     pw.print(" waitingToHide="); pw.print(waitingToHide);
                     pw.print(" sendingToBottom="); pw.print(sendingToBottom);
-                    pw.print(" sendingToTop="); pw.println(sendingToTop);
         }
     }
 
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
index a47f8fd..0904bdd 100644
--- a/services/jni/com_android_server_PowerManagerService.cpp
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -83,11 +83,9 @@
 }
 
 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
-    if (gPowerModule) {
-        // Tell the power HAL when user activity occurs.
-        if (gPowerModule->powerHint) {
-            gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
-        }
+    // Tell the power HAL when user activity occurs.
+    if (gPowerModule && gPowerModule->powerHint) {
+        gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
     }
 
     if (gPowerManagerServiceObj) {
@@ -131,16 +129,11 @@
 
     status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
             (hw_module_t const**)&gPowerModule);
-    if (err) {
-        String8 msg;
-        msg.appendFormat("Couldn't load %s module (%s)",
-                POWER_HARDWARE_MODULE_ID, strerror(-err));
-        ALOGE("%s", msg.string());
-        jniThrowRuntimeException(env, msg.string());
-        return;
+    if (!err) {
+        gPowerModule->init(gPowerModule);
+    } else {
+        ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
     }
-
-    gPowerModule->init(gPowerModule);
 }
 
 static void nativeSetPowerState(JNIEnv* env,
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cc3c328..3f66de6 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -37,13 +37,15 @@
     <application>
         <uses-library android:name="android.test.runner" />
 
-        <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService">
+        <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
           <intent-filter>
             <action android:name="android.accessibilityservice.AccessibilityService"/>
           </intent-filter>
         </service>
 
-        <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService">
+        <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
           <intent-filter>
             <action android:name="android.accessibilityservice.AccessibilityService"/>
           </intent-filter>
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 332d198..cdc4d78 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -777,10 +777,80 @@
 
     }
 
+    public void testReportXtOverDev() throws Exception {
+        // bring mobile network online
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkState(buildMobile3gState(IMSI_1));
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectNetworkStatsPoll();
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        verifyAndReset();
+
+        // create some traffic, but only for DEV, and across 1.5 buckets
+        incrementCurrentTime(90 * MINUTE_IN_MILLIS);
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1)
+                .addIfaceValues(TEST_IFACE, 6000L, 60L, 3000L, 30L));
+        expectNetworkStatsSummaryXt(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectNetworkStatsPoll();
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history:
+        // 4000(dev) + 2000(dev)
+        assertNetworkTotal(sTemplateImsi1, 6000L, 60L, 3000L, 30L, 0);
+        verifyAndReset();
+
+        // create traffic on both DEV and XT, across two buckets
+        incrementCurrentTime(2 * HOUR_IN_MILLIS);
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1)
+                .addIfaceValues(TEST_IFACE, 6004L, 64L, 3004L, 34L));
+        expectNetworkStatsSummaryXt(new NetworkStats(getElapsedRealtime(), 1)
+                .addIfaceValues(TEST_IFACE, 10240L, 0L, 0L, 0L));
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectNetworkStatsPoll();
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify that we switching reporting at the first atomic XT bucket,
+        // which should give us:
+        // 4000(dev) + 2000(dev) + 1(dev) + 5120(xt) + 2560(xt)
+        assertNetworkTotal(sTemplateImsi1, 13681L, 61L, 3001L, 31L, 0);
+
+        // also test pure-DEV and pure-XT ranges
+        assertNetworkTotal(sTemplateImsi1, startTimeMillis(),
+                startTimeMillis() + 2 * HOUR_IN_MILLIS, 6001L, 61L, 3001L, 31L, 0);
+        assertNetworkTotal(sTemplateImsi1, startTimeMillis() + 2 * HOUR_IN_MILLIS,
+                startTimeMillis() + 4 * HOUR_IN_MILLIS, 7680L, 0L, 0L, 0L, 0);
+
+        verifyAndReset();
+    }
+
     private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
             long txBytes, long txPackets, int operations) throws Exception {
+        assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
+                txPackets, operations);
+    }
+
+    private void assertNetworkTotal(NetworkTemplate template, long start, long end, long rxBytes,
+            long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
+        // verify history API
         final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
-        assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
+        assertValues(history, start, end, rxBytes, rxPackets, txBytes, txPackets, operations);
+
+        // verify summary API
+        final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
+        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
     }
 
@@ -791,10 +861,17 @@
 
     private void assertUidTotal(NetworkTemplate template, int uid, int set, long rxBytes,
             long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
+        // verify history API
         final NetworkStatsHistory history = mSession.getHistoryForUid(
                 template, uid, set, TAG_NONE, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
+
+        // verify summary API
+        final NetworkStats stats = mSession.getSummaryForAllUid(
+                template, Long.MIN_VALUE, Long.MAX_VALUE, false);
+        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
+                operations);
     }
 
     private void expectSystemReady() throws Exception {
@@ -819,7 +896,15 @@
     }
 
     private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
+        expectNetworkStatsSummaryDev(summary);
+        expectNetworkStatsSummaryXt(summary);
+    }
+
+    private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
         expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce();
+    }
+
+    private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
         expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce();
     }
 
@@ -847,6 +932,7 @@
         expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
         expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
         expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
+        expect(mSettings.getReportXtOverDev()).andReturn(true).anyTimes();
 
         final Config config = new Config(bucketDuration, deleteAge, deleteAge);
         expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
@@ -885,8 +971,20 @@
 
     private static void assertValues(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) {
-        final int i = stats.findIndex(iface, uid, set, tag);
-        final NetworkStats.Entry entry = stats.getValues(i, null);
+        final NetworkStats.Entry entry = new NetworkStats.Entry();
+        if (set == SET_DEFAULT || set == SET_ALL) {
+            final int i = stats.findIndex(iface, uid, SET_DEFAULT, tag);
+            if (i != -1) {
+                entry.add(stats.getValues(i, null));
+            }
+        }
+        if (set == SET_FOREGROUND || set == SET_ALL) {
+            final int i = stats.findIndex(iface, uid, SET_FOREGROUND, tag);
+            if (i != -1) {
+                entry.add(stats.getValues(i, null));
+            }
+        }
+
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
index 8634821..1a6c289 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
@@ -16,7 +16,11 @@
 
 package com.android.server.net;
 
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
 import android.content.res.Resources;
@@ -47,6 +51,14 @@
     private static final String TEST_FILE = "test.bin";
     private static final String TEST_IMSI = "310260000000000";
 
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // ignore any device overlay while testing
+        NetworkTemplate.forceAllNetworkTypes();
+    }
+
     public void testReadLegacyNetwork() throws Exception {
         final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
         stageFile(R.raw.netstats_v1, testFile);
@@ -125,6 +137,20 @@
                 77017831L, 100995L, 35436758L, 92344L);
     }
 
+    public void testStartEndAtomicBuckets() throws Exception {
+        final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
+
+        // record empty data straddling between buckets
+        final NetworkStats.Entry entry = new NetworkStats.Entry();
+        entry.rxBytes = 32;
+        collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS,
+                90 * MINUTE_IN_MILLIS, entry);
+
+        // assert that we report boundary in atomic buckets
+        assertEquals(0, collection.getStartMillis());
+        assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
+    }
+
     /**
      * Copy a {@link Resources#openRawResource(int)} into {@link File} for
      * testing purposes.
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index e984a87..3a3044e 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -78,8 +78,11 @@
         return mDataConnection;
     }
 
-    public synchronized void setDataConnection(DataConnection dataConnection) {
-        mDataConnection = dataConnection;
+    public synchronized void setDataConnection(DataConnection dc) {
+        if (DBG) {
+            log("setDataConnection: old dc=" + mDataConnection + " new dc=" + dc + " this=" + this);
+        }
+        mDataConnection = dc;
     }
 
 
@@ -88,10 +91,15 @@
     }
 
     public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
+        if (DBG) {
+            log("setDataConnectionAc: old dcac=" + mDataConnectionAc + " new dcac=" + dcac);
+        }
         if (dcac != null) {
             dcac.addApnContextSync(this);
         } else {
-            if (mDataConnectionAc != null) mDataConnectionAc.removeApnContextSync(this);
+            if (mDataConnectionAc != null) {
+                mDataConnectionAc.removeApnContextSync(this);
+            }
         }
         mDataConnectionAc = dcac;
     }
@@ -141,7 +149,7 @@
 
     public synchronized void setState(DataConnectionTracker.State s) {
         if (DBG) {
-            log("setState: " + s + " for type " + mApnType + ", previous state:" + mState);
+            log("setState: " + s + ", previous state:" + mState);
         }
 
         mState = s;
@@ -165,7 +173,7 @@
 
     public synchronized void setReason(String reason) {
         if (DBG) {
-            log("set reason as " + reason + ", for type " + mApnType + ",current state " + mState);
+            log("set reason as " + reason + ",current state " + mState);
         }
         mReason = reason;
     }
@@ -180,8 +188,7 @@
 
     public void setEnabled(boolean enabled) {
         if (DBG) {
-            log("set enabled as " + enabled + ", for type " +
-                    mApnType + ", current state is " + mDataEnabled.get());
+            log("set enabled as " + enabled + ", current state is " + mDataEnabled.get());
         }
         mDataEnabled.set(enabled);
     }
@@ -192,8 +199,7 @@
 
     public void setDependencyMet(boolean met) {
         if (DBG) {
-            log("set mDependencyMet as " + met + ", for type " + mApnType +
-                    ", current state is " + mDependencyMet.get());
+            log("set mDependencyMet as " + met + " current state is " + mDependencyMet.get());
         }
         mDependencyMet.set(met);
     }
@@ -204,25 +210,19 @@
 
     @Override
     public String toString() {
-        return "state=" + getState() + " apnType=" + mApnType;
+        // We don't print mDataConnection because its recursive.
+        return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns=" + mWaitingApns +
+                " mWaitingApnsPermanentFailureCountDown=" + mWaitingApnsPermanentFailureCountDown +
+                " mApnSetting=" + mApnSetting + " mDataConnectionAc=" + mDataConnectionAc +
+                " mReason=" + mReason + " mDataEnabled=" + mDataEnabled +
+                " mDependencyMet=" + mDependencyMet + "}";
     }
 
     protected void log(String s) {
-        Log.d(LOG_TAG, "[ApnContext] " + s);
+        Log.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s);
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("ApnContext:");
-        pw.println(" mApnType=" + mApnType);
-        pw.println(" mState=" + mState);
-        pw.println(" mWaitingApns=" + mWaitingApns);
-        pw.println(" mWaitingApnsPermanentFailureCountDown=" +
-                            mWaitingApnsPermanentFailureCountDown);
-        pw.println(" mApnSetting=" + mApnSetting);
-        pw.println(" mDataConnection=" + mDataConnection);
-        pw.println(" mDataConnectionAc=" + mDataConnectionAc);
-        pw.println(" mReason=" + mReason);
-        pw.println(" mDataEnabled=" + mDataEnabled);
-        pw.println(" mDependencyMet=" + mDependencyMet);
+        pw.println("ApnContext: " + this.toString());
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 7c70a7e..cc4adfd 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -69,7 +69,7 @@
     protected static int mCount;
     protected AsyncChannel mAc;
 
-    private List<ApnContext> mApnList = null;
+    protected List<ApnContext> mApnList = null;
     PendingIntent mReconnectIntent = null;
 
     private DataConnectionTracker mDataConnectionTracker = null;
@@ -247,7 +247,7 @@
     protected FailCause lastFailCause;
     protected int mRetryOverride = -1;
     protected static final String NULL_IP = "0.0.0.0";
-    private int mRefCount;
+    protected int mRefCount;
     Object userData;
 
     //***** Abstract methods
@@ -600,9 +600,8 @@
         result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
 
         if (DBG && (! result.oldLp.equals(result.newLp))) {
-            if (DBG) log("updateLinkProperty old != new");
-            if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
-            if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
+            log("updateLinkProperty old LP=" + result.oldLp);
+            log("updateLinkProperty new LP=" + result.newLp);
         }
         mLinkProperties = result.newLp;
 
@@ -1256,6 +1255,7 @@
         pw.println(" mRetryOverride=" + mRetryOverride);
         pw.println(" mRefCount=" + mRefCount);
         pw.println(" userData=" + userData);
+        if (mRetryMgr != null) pw.println(" " + mRetryMgr);
         pw.flush();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 96419ae..a24414f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -580,6 +580,11 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return dataConnection.getName();
+    }
+
     private void log(String s) {
         android.util.Log.d(mLogTag, "DataConnectionAc " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 97a8755..588515b 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -499,6 +499,7 @@
      */
     protected DataConnectionTracker(PhoneBase phone) {
         super();
+        if (DBG) log("DCT.constructor");
         mPhone = phone;
 
         IntentFilter filter = new IntentFilter();
@@ -534,6 +535,7 @@
     }
 
     public void dispose() {
+        if (DBG) log("DCT.dispose");
         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
             dcac.disconnect();
         }
@@ -1256,7 +1258,6 @@
             Set<Entry<String, ApnContext>> mApnContextsSet = mApnContexts.entrySet();
             pw.println(" mApnContexts size=" + mApnContextsSet.size());
             for (Entry<String, ApnContext> entry : mApnContextsSet) {
-                pw.printf(" *** mApnContexts[%s]:\n", entry.getKey());
                 entry.getValue().dump(fd, pw, args);
             }
             pw.println(" ***************************************");
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d738d7b..fcf2f92 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -579,10 +579,14 @@
             mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
         }
 
-        // Call onReady only when SIM or RUIM card becomes ready (not NV)
+        // Call onReady Record(s) on the IccCard becomes ready (not NV)
         if (oldState != State.READY && newState == State.READY &&
                 (is3gpp || isSubscriptionFromIccCard)) {
-            mIccFileHandler.setAid(getAid());
+            if (!(mIccFileHandler instanceof CdmaLteUiccFileHandler)) {
+                // CdmaLteUicc File Handler deals with both USIM and CSIM.
+                // Do not lock onto one AID for now.
+                mIccFileHandler.setAid(getAid());
+            }
             mIccRecords.onReady();
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
index 29bd104..ae451b9 100644
--- a/telephony/java/com/android/internal/telephony/RetryManager.java
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -74,7 +74,8 @@
  */
 public class RetryManager {
     static public final String LOG_TAG = "RetryManager";
-    static public final boolean DBG = false;
+    static public final boolean DBG = true;
+    static public final boolean VDBG = false;
 
     /**
      * Retry record with times in milli-seconds
@@ -107,9 +108,20 @@
     /** Random number generator */
     private Random rng = new Random();
 
+    private String mConfig;
+
     /** Constructor */
     public RetryManager() {
-        if (DBG) log("constructor");
+        if (VDBG) log("constructor");
+    }
+
+    public String toString() {
+        String ret = "RetryManager: forever=" + mRetryForever + ", maxRetry=" + mMaxRetryCount +
+                ", retry=" + mRetryCount + ",\n    " + mConfig;
+        for (RetryRec r : mRetryArray) {
+            ret += "\n    " + r.mDelayTime + ":" + r.mRandomizationTime;
+        }
+        return ret;
     }
 
     /**
@@ -127,7 +139,7 @@
     public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
         Pair<Boolean, Integer> value;
 
-        if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
+        if (VDBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
 
         if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) {
             return false;
@@ -161,12 +173,13 @@
         if ((configStr.startsWith("\"") && configStr.endsWith("\""))) {
             configStr = configStr.substring(1, configStr.length()-1);
         }
-        if (DBG) log("configure: '" + configStr + "'");
+        if (VDBG) log("configure: '" + configStr + "'");
+        mConfig = configStr;
 
         if (!TextUtils.isEmpty(configStr)) {
             int defaultRandomization = 0;
 
-            if (DBG) log("configure: not empty");
+            if (VDBG) log("configure: not empty");
 
             mMaxRetryCount = 0;
             resetRetryCount();
@@ -174,14 +187,14 @@
 
             String strArray[] = configStr.split(",");
             for (int i = 0; i < strArray.length; i++) {
-                if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
+                if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
                 Pair<Boolean, Integer> value;
                 String splitStr[] = strArray[i].split("=", 2);
                 splitStr[0] = splitStr[0].trim();
-                if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
+                if (VDBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
                 if (splitStr.length > 1) {
                     splitStr[1] = splitStr[1].trim();
-                    if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+                    if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
                     if (TextUtils.equals(splitStr[0], "default_randomization")) {
                         value = parseNonNegativeInt(splitStr[0], splitStr[1]);
                         if (!value.first) return false;
@@ -214,7 +227,7 @@
                     // Check if optional randomization value present
                     if (splitStr.length > 1) {
                         splitStr[1] = splitStr[1].trim();
-                        if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+                        if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
                         value = parseNonNegativeInt("randomizationTime", splitStr[1]);
                         if (!value.first) return false;
                         rr.mRandomizationTime = value.second;
@@ -226,12 +239,12 @@
             }
             if (mRetryArray.size() > mMaxRetryCount) {
                 mMaxRetryCount = mRetryArray.size();
-                if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
+                if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
             }
-            if (DBG) log("configure: true");
+            if (VDBG) log("configure: true");
             return true;
         } else {
-            if (DBG) log("configure: false it's empty");
+            if (VDBG) log("configure: false it's empty");
             return false;
         }
     }
@@ -349,7 +362,7 @@
             Log.e(LOG_TAG, name + " bad value: " + stringValue, e);
             retVal = new Pair<Boolean, Integer>(false, 0);
         }
-        if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+        if (VDBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
                     + retVal.first + ", " + retVal.second);
         return retVal;
     }
@@ -369,7 +382,7 @@
         } else {
             retVal = true;
         }
-        if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
+        if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
         return retVal;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 69dd666..e4cfb23 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -146,6 +146,7 @@
         "ci", // Cote d'Ivoire
         "eh", // Western Sahara
         "fo", // Faroe Islands, Denmark
+        "gb", // United Kingdom of Great Britain and Northern Ireland
         "gh", // Ghana
         "gm", // Gambia
         "gn", // Guinea
@@ -161,7 +162,6 @@
         "sn", // Senegal
         "st", // Sao Tome and Principe
         "tg", // Togo
-        "uk", // U.K
     };
 
     /** Reason for registration denial. */
diff --git a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java
index 07a0a28..f40958d 100644
--- a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -19,15 +19,21 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Message;
 import android.provider.Settings;
 import android.telephony.PhoneNumberUtils;
 import android.util.Log;
 
 import com.android.internal.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
 
 import java.io.IOException;
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -45,6 +51,8 @@
  */
 public class SmsUsageMonitor {
     private static final String TAG = "SmsUsageMonitor";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
 
     /** Default checking period for SMS sent without user permission. */
     private static final int DEFAULT_SMS_CHECK_PERIOD = 1800000;    // 30 minutes
@@ -69,6 +77,7 @@
 
     private final int mCheckPeriod;
     private final int mMaxAllowed;
+
     private final HashMap<String, ArrayList<Long>> mSmsStamp =
             new HashMap<String, ArrayList<Long>>();
 
@@ -87,6 +96,12 @@
     /** Cached short code pattern matcher for {@link #mCurrentCountry}. */
     private ShortCodePatternMatcher mCurrentPatternMatcher;
 
+    /** Cached short code regex patterns from secure settings for {@link #mCurrentCountry}. */
+    private String mSettingsShortCodePatterns;
+
+    /** Handler for responding to content observer updates. */
+    private final SettingsObserverHandler mSettingsObserverHandler;
+
     /** XML tag for root element. */
     private static final String TAG_SHORTCODES = "shortcodes";
 
@@ -149,6 +164,74 @@
     }
 
     /**
+     * Observe the secure setting for updated regex patterns.
+     */
+    private static class SettingsObserver extends ContentObserver {
+        private final int mWhat;
+        private final Handler mHandler;
+
+        SettingsObserver(Handler handler, int what) {
+            super(handler);
+            mHandler = handler;
+            mWhat = what;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mHandler.obtainMessage(mWhat).sendToTarget();
+        }
+    }
+
+    /**
+     * Handler to update regex patterns when secure setting for the current country is updated.
+     */
+    private class SettingsObserverHandler extends Handler {
+        /** Current content observer, or null. */
+        SettingsObserver mSettingsObserver;
+
+        /** Current country code to watch for settings updates. */
+        private String mCountryIso;
+
+        /** Request to start observing a secure setting. */
+        static final int OBSERVE_SETTING = 1;
+
+        /** Handler event for updated secure settings. */
+        static final int SECURE_SETTINGS_CHANGED = 2;
+
+        /** Send a message to this handler requesting to observe the setting for a new country. */
+        void observeSettingForCountry(String countryIso) {
+            obtainMessage(OBSERVE_SETTING, countryIso).sendToTarget();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case OBSERVE_SETTING:
+                    if (msg.obj != null && msg.obj instanceof String) {
+                        mCountryIso = (String) msg.obj;
+                        String settingName = getSettingNameForCountry(mCountryIso);
+                        ContentResolver resolver = mContext.getContentResolver();
+
+                        if (mSettingsObserver != null) {
+                            if (VDBG) log("Unregistering old content observer");
+                            resolver.unregisterContentObserver(mSettingsObserver);
+                        }
+
+                        mSettingsObserver = new SettingsObserver(this, SECURE_SETTINGS_CHANGED);
+                        resolver.registerContentObserver(
+                                Settings.Secure.getUriFor(settingName), false, mSettingsObserver);
+                        if (VDBG) log("Registered content observer for " + settingName);
+                    }
+                    break;
+
+                case SECURE_SETTINGS_CHANGED:
+                    loadPatternsFromSettings(mCountryIso);
+                    break;
+            }
+        }
+    }
+
+    /**
      * Create SMS usage monitor.
      * @param context the context to use to load resources and get TelephonyManager service
      */
@@ -164,6 +247,8 @@
                 Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS,
                 DEFAULT_SMS_CHECK_PERIOD);
 
+        mSettingsObserverHandler = new SettingsObserverHandler();
+
         // system MMS app is always allowed to send to short codes
         mApprovedShortCodeSenders.add("com.android.mms");
     }
@@ -178,27 +263,7 @@
         XmlResourceParser parser = mContext.getResources().getXml(id);
 
         try {
-            XmlUtils.beginDocument(parser, TAG_SHORTCODES);
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-
-                String element = parser.getName();
-                if (element == null) break;
-
-                if (element.equals(TAG_SHORTCODE)) {
-                    String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY);
-                    if (country.equals(currentCountry)) {
-                        String pattern = parser.getAttributeValue(null, ATTR_PATTERN);
-                        String premium = parser.getAttributeValue(null, ATTR_PREMIUM);
-                        String free = parser.getAttributeValue(null, ATTR_FREE);
-                        String standard = parser.getAttributeValue(null, ATTR_STANDARD);
-                        return new ShortCodePatternMatcher(pattern, premium, free, standard);
-                    }
-                } else {
-                    Log.e(TAG, "Error: skipping unknown XML tag " + element);
-                }
-            }
+            return getPatternMatcher(country, parser);
         } catch (XmlPullParserException e) {
             Log.e(TAG, "XML parser exception reading short code pattern resource", e);
         } catch (IOException e) {
@@ -209,6 +274,60 @@
         return null;    // country not found
     }
 
+    /**
+     * Return a pattern matcher object for the specified country from a secure settings string.
+     * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found
+     */
+    private static ShortCodePatternMatcher getPatternMatcher(String country, String settingsPattern) {
+        // embed pattern tag into an XML document.
+        String document = "<shortcodes>" + settingsPattern + "</shortcodes>";
+        if (VDBG) log("loading updated patterns from: " + document);
+
+        try {
+            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+            XmlPullParser parser = factory.newPullParser();
+            parser.setInput(new StringReader(document));
+            return getPatternMatcher(country, parser);
+        } catch (XmlPullParserException e) {
+            Log.e(TAG, "XML parser exception reading short code pattern from settings", e);
+        } catch (IOException e) {
+            Log.e(TAG, "I/O exception reading short code pattern from settings", e);
+        }
+        return null;    // country not found
+    }
+
+    /**
+     * Return a pattern matcher object for the specified country and pattern XML parser.
+     * @param country the country to search for
+     * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found
+     */
+    private static ShortCodePatternMatcher getPatternMatcher(String country, XmlPullParser parser)
+            throws XmlPullParserException, IOException
+    {
+        XmlUtils.beginDocument(parser, TAG_SHORTCODES);
+
+        while (true) {
+            XmlUtils.nextElement(parser);
+
+            String element = parser.getName();
+            if (element == null) break;
+
+            if (element.equals(TAG_SHORTCODE)) {
+                String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY);
+                if (country.equals(currentCountry)) {
+                    String pattern = parser.getAttributeValue(null, ATTR_PATTERN);
+                    String premium = parser.getAttributeValue(null, ATTR_PREMIUM);
+                    String free = parser.getAttributeValue(null, ATTR_FREE);
+                    String standard = parser.getAttributeValue(null, ATTR_STANDARD);
+                    return new ShortCodePatternMatcher(pattern, premium, free, standard);
+                }
+            } else {
+                Log.e(TAG, "Error: skipping unknown XML tag " + element);
+            }
+        }
+        return null;    // country not found
+    }
+
     /** Clear the SMS application list for disposal. */
     void dispose() {
         mSmsStamp.clear();
@@ -244,7 +363,9 @@
      * @return true if the app is approved; false if we need to confirm short code destinations
      */
     public boolean isApprovedShortCodeSender(String appName) {
-        return mApprovedShortCodeSenders.contains(appName);
+        synchronized (mApprovedShortCodeSenders) {
+            return mApprovedShortCodeSenders.contains(appName);
+        }
     }
 
     /**
@@ -252,8 +373,10 @@
      * @param appName the package name of the app to add
      */
     public void addApprovedShortCodeSender(String appName) {
-        Log.d(TAG, "Adding " + appName + " to list of approved short code senders.");
-        mApprovedShortCodeSenders.add(appName);
+        if (DBG) log("Adding " + appName + " to list of approved short code senders.");
+        synchronized (mApprovedShortCodeSenders) {
+            mApprovedShortCodeSenders.add(appName);
+        }
     }
 
     /**
@@ -271,32 +394,71 @@
      *  {@link #CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, or {@link #CATEGORY_PREMIUM_SHORT_CODE}.
      */
     public int checkDestination(String destAddress, String countryIso) {
-        // always allow emergency numbers
-        if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) {
-            return CATEGORY_NOT_SHORT_CODE;
-        }
+        synchronized (mSettingsObserverHandler) {
+            // always allow emergency numbers
+            if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) {
+                return CATEGORY_NOT_SHORT_CODE;
+            }
 
-        ShortCodePatternMatcher patternMatcher = null;
+            ShortCodePatternMatcher patternMatcher = null;
 
-        if (countryIso != null) {
-            if (countryIso.equals(mCurrentCountry)) {
-                patternMatcher = mCurrentPatternMatcher;
+            if (countryIso != null) {
+                // query secure settings and initialize content observer for updated regex patterns
+                if (mCurrentCountry == null || !countryIso.equals(mCurrentCountry)) {
+                    loadPatternsFromSettings(countryIso);
+                    mSettingsObserverHandler.observeSettingForCountry(countryIso);
+                }
+
+                if (countryIso.equals(mCurrentCountry)) {
+                    patternMatcher = mCurrentPatternMatcher;
+                } else {
+                    patternMatcher = getPatternMatcher(countryIso);
+                    mCurrentCountry = countryIso;
+                    mCurrentPatternMatcher = patternMatcher;    // may be null if not found
+                }
+            }
+
+            if (patternMatcher != null) {
+                return patternMatcher.getNumberCategory(destAddress);
             } else {
-                patternMatcher = getPatternMatcher(countryIso);
-                mCurrentCountry = countryIso;
-                mCurrentPatternMatcher = patternMatcher;    // may be null if not found
+                // Generic rule: numbers of 5 digits or less are considered potential short codes
+                Log.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule");
+                if (destAddress.length() <= 5) {
+                    return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
+                } else {
+                    return CATEGORY_NOT_SHORT_CODE;
+                }
             }
         }
+    }
 
-        if (patternMatcher != null) {
-            return patternMatcher.getNumberCategory(destAddress);
-        } else {
-            // Generic rule: numbers of 5 digits or less are considered potential short codes
-            Log.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule");
-            if (destAddress.length() <= 5) {
-                return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
-            } else {
-                return CATEGORY_NOT_SHORT_CODE;
+    private static String getSettingNameForCountry(String countryIso) {
+        return Settings.Secure.SMS_SHORT_CODES_PREFIX + countryIso;
+    }
+
+    /**
+     * Load regex patterns from secure settings if present.
+     * @param countryIso the country to search for
+     */
+    void loadPatternsFromSettings(String countryIso) {
+        synchronized (mSettingsObserverHandler) {
+            if (VDBG) log("loadPatternsFromSettings(" + countryIso + ") called");
+            String settingsPatterns = Settings.Secure.getString(
+                    mContext.getContentResolver(), getSettingNameForCountry(countryIso));
+            if (settingsPatterns != null && !settingsPatterns.equals(
+                    mSettingsShortCodePatterns)) {
+                // settings pattern string has changed: update the pattern matcher
+                mSettingsShortCodePatterns = settingsPatterns;
+                ShortCodePatternMatcher matcher = getPatternMatcher(countryIso, settingsPatterns);
+                if (matcher != null) {
+                    mCurrentCountry = countryIso;
+                    mCurrentPatternMatcher = matcher;
+                }
+            } else if (settingsPatterns == null && mSettingsShortCodePatterns != null) {
+                // pattern string was removed: caller will load default patterns from XML resource
+                mCurrentCountry = null;
+                mCurrentPatternMatcher = null;
+                mSettingsShortCodePatterns = null;
             }
         }
     }
@@ -324,7 +486,7 @@
         Long ct = System.currentTimeMillis();
         long beginCheckPeriod = ct - mCheckPeriod;
 
-        Log.d(TAG, "SMS send size=" + sent.size() + " time=" + ct);
+        if (VDBG) log("SMS send size=" + sent.size() + " time=" + ct);
 
         while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) {
             sent.remove(0);
@@ -338,4 +500,8 @@
         }
         return false;
     }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index e4287c0..25cd112 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -293,8 +293,15 @@
                         EVENT_RUIM_RECORDS_LOADED, null);
                 mNeedToRegForRuimLoaded = false;
             }
-            if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
-            getSubscriptionInfoAndStartPollingThreads();
+
+            if (phone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) {
+                // Subscription will be read from SIM I/O
+                if (DBG) log("Receive EVENT_RUIM_READY");
+                pollState();
+            } else {
+                if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
+                getSubscriptionInfoAndStartPollingThreads();
+            }
             phone.prepareEri();
             break;
 
@@ -878,19 +885,22 @@
             // For NITZ string without time zone,
             // need adjust time to reflect default time zone setting
             zone = TimeZone.getDefault();
-            long ctm = System.currentTimeMillis();
-            long tzOffset = zone.getOffset(ctm);
-            if (DBG) {
-                log("fixTimeZone: tzOffset=" + tzOffset + " ltod=" + TimeUtils.logTimeOfDay(ctm));
-            }
-            if (getAutoTime()) {
-                long adj = ctm - tzOffset;
-                if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj));
-                setAndBroadcastNetworkSetTime(adj);
-            } else {
-                // Adjust the saved NITZ time to account for tzOffset.
-                mSavedTime = mSavedTime - tzOffset;
-                if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime);
+            if (mNeedFixZone) {
+                long ctm = System.currentTimeMillis();
+                long tzOffset = zone.getOffset(ctm);
+                if (DBG) {
+                    log("fixTimeZone: tzOffset=" + tzOffset +
+                            " ltod=" + TimeUtils.logTimeOfDay(ctm));
+                }
+                if (getAutoTime()) {
+                    long adj = ctm - tzOffset;
+                    if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj));
+                    setAndBroadcastNetworkSetTime(adj);
+                } else {
+                    // Adjust the saved NITZ time to account for tzOffset.
+                    mSavedTime = mSavedTime - tzOffset;
+                    if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime);
+                }
             }
             if (DBG) log("fixTimeZone: using default TimeZone");
         } else if (isoCountryCode.equals("")) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index df3278b..9801721 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -120,9 +120,10 @@
 
     @Override
     public String toString() {
-        return "State=" + getCurrentState().getName() + " Apn=" + mApn +
-               " create=" + createTime + " lastFail=" + lastFailTime +
-               " lastFailCause=" + lastFailCause;
+        return "{" + getName() + ": State=" + getCurrentState().getName() +
+                " apnSetting=" + mApn + " apnList= " + mApnList + " RefCount=" + mRefCount +
+                " cid=" + cid + " create=" + createTime + " lastFail=" + lastFailTime +
+                " lastFailCause=" + lastFailCause + "}";
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index e2579e3..83fc9c1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -175,7 +175,7 @@
 
     public GsmDataConnectionTracker(PhoneBase p) {
         super(p);
-
+        if (DBG) log("GsmDCT.constructor");
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
@@ -212,6 +212,7 @@
 
     @Override
     public void dispose() {
+        if (DBG) log("GsmDCT.dispose");
         cleanUpAllConnections(false, null);
 
         super.dispose();
@@ -835,10 +836,11 @@
             return;
         }
 
-        if (DBG) {
-            log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
-        }
         DataConnectionAc dcac = apnContext.getDataConnectionAc();
+        if (DBG) {
+            log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() +
+                    " apnContext=" + apnContext);
+        }
         if (tearDown) {
             if (apnContext.isDisconnected()) {
                 // The request is tearDown and but ApnContext is not connected.
@@ -901,6 +903,10 @@
                 cancelReconnectAlarm(dcac);
             }
         }
+        if (DBG) {
+            log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() +
+                    " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
+        }
     }
 
     /**
@@ -986,8 +992,12 @@
     private GsmDataConnection findFreeDataConnection() {
         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
             if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
-                log("findFreeDataConnection: found free GsmDataConnection");
-                return (GsmDataConnection) dcac.dataConnection;
+                DataConnection dc = dcac.dataConnection;
+                if (DBG) {
+                    log("findFreeDataConnection: found free GsmDataConnection=" +
+                        " dcac=" + dcac + " dc=" + dc);
+                }
+                return (GsmDataConnection) dc;
             }
         }
         log("findFreeDataConnection: NO free GsmDataConnection");
@@ -995,12 +1005,13 @@
     }
 
     protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
-        if (DBG)
-            log("findReadyDataConnection: apn string <" +
-                (apn!=null?(apn.toString()):"null") +">");
         if (apn == null) {
             return null;
         }
+        if (DBG) {
+            log("findReadyDataConnection: apn string <" + apn + ">" +
+                    " dcacs.size=" + mDataConnectionAsyncChannels.size());
+        }
         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
             ApnSetting apnSetting = dcac.getApnSettingSync();
             if (DBG) {
@@ -1008,7 +1019,12 @@
                          (apnSetting != null ? (apnSetting.toString()) : "null") + ">");
             }
             if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) {
-                return (GsmDataConnection) dcac.dataConnection;
+                DataConnection dc = dcac.dataConnection;
+                if (DBG) {
+                    log("findReadyDataConnection: found ready GsmDataConnection=" +
+                        " dcac=" + dcac + " dc=" + dc);
+                }
+                return (GsmDataConnection) dc;
             }
         }
         return null;
@@ -1129,6 +1145,8 @@
     private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
         if (dcacs == null) return null;
 
+        if (DBG) log("findApnContextToClean(ar): E dcacs=" + dcacs);
+
         ArrayList<ApnContext> list = new ArrayList<ApnContext>();
         for (ApnContext apnContext : mApnContexts.values()) {
             if (apnContext.getState() == State.CONNECTED) {
@@ -1144,7 +1162,7 @@
                     // ApnContext does not have dcac reported in data call list.
                     // Fetch all the ApnContexts that map to this dcac which are in
                     // INITING state too.
-                    if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" +
+                    if (DBG) log("findApnContextToClean(ar): Connected apn not found in the list (" +
                                  apnContext.toString() + ")");
                     if (apnContext.getDataConnectionAc() != null) {
                         list.addAll(apnContext.getDataConnectionAc().getApnListSync());
@@ -1154,6 +1172,7 @@
                 }
             }
         }
+        if (DBG) log("findApnContextToClean(ar): X list=" + list);
         return list;
     }
 
@@ -1236,6 +1255,10 @@
                                 // If the same address type was removed and added we need to cleanup
                                 CompareResult<LinkAddress> car =
                                     result.oldLp.compareAddresses(result.newLp);
+                                if (DBG) {
+                                    log("onDataStateChanged: oldLp=" + result.oldLp +
+                                            " newLp=" + result.newLp + " car=" + car);
+                                }
                                 boolean needToClean = false;
                                 for (LinkAddress added : car.added) {
                                     for (LinkAddress removed : car.removed) {
@@ -1249,7 +1272,8 @@
                                 if (needToClean) {
                                     if (DBG) {
                                         log("onDataStateChanged(ar): addr change, cleanup apns=" +
-                                                connectedApns);
+                                                connectedApns + " oldLp=" + result.oldLp +
+                                                " newLp=" + result.newLp);
                                     }
                                     apnsToCleanup.addAll(connectedApns);
                                 } else {
@@ -1285,6 +1309,7 @@
         }
 
         // Cleanup those dropped connections
+        if (DBG) log("onDataStateChange(ar): apnsToCleanup=" + apnsToCleanup);
         for (ApnContext apnContext : apnsToCleanup) {
             cleanUpConnection(true, apnContext);
         }
@@ -1695,6 +1720,7 @@
 
     @Override
     protected void restartDataStallAlarm() {
+        if (isConnected() == false) return;
         // To be called on screen status change.
         // Do not cancel the alarm if it is set with aggressive timeout.
         int nextAction = getRecoveryAction();
@@ -2141,10 +2167,9 @@
                 // clean slate after call end.
                 resetPollStats();
             }
-        } else {
-            // reset reconnect timer
-            setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
         }
+        // reset reconnect timer
+        setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
     }
 
     @Override
@@ -2256,7 +2281,7 @@
         filter.addAction(INTENT_RECONNECT_ALARM + '.' + id);
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
 
-        if (DBG) log("createDataConnection() X id=" + id);
+        if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
         return conn;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 1aa17c7..b7569da 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -111,7 +111,7 @@
      * are in. Keep the time zone information from the NITZ string so
      * we can fix the time zone once know the country.
      */
-    private boolean mNeedFixZone = false;
+    private boolean mNeedFixZoneAfterNitz = false;
     private int mZoneOffset;
     private boolean mZoneDst;
     private long mZoneTime;
@@ -906,7 +906,7 @@
                 }
 
                 if (shouldFixTimeZoneNow(phone, operatorNumeric, prevOperatorNumeric,
-                        mNeedFixZone)) {
+                        mNeedFixZoneAfterNitz)) {
                     // If the offset is (0, false) and the timezone property
                     // is set, use the timezone property rather than
                     // GMT.
@@ -917,25 +917,35 @@
                             " iso-cc='" + iso +
                             "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
                     }
+
+                    // "(mZoneOffset == 0) && (mZoneDst == false) &&
+                    //  (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)"
+                    // means that we received a NITZ string telling
+                    // it is in GMT+0 w/ DST time zone
+                    // BUT iso tells is NOT, e.g, a wrong NITZ reporting
+                    // local time w/ 0 offset.
                     if ((mZoneOffset == 0) && (mZoneDst == false) &&
                         (zoneName != null) && (zoneName.length() > 0) &&
                         (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
                         zone = TimeZone.getDefault();
-                        // For NITZ string without timezone,
-                        // need adjust time to reflect default timezone setting
-                        long ctm = System.currentTimeMillis();
-                        long tzOffset = zone.getOffset(ctm);
-                        if (DBG) {
-                            log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
+                        if (mNeedFixZoneAfterNitz) {
+                            // For wrong NITZ reporting local time w/ 0 offset,
+                            // need adjust time to reflect default timezone setting
+                            long ctm = System.currentTimeMillis();
+                            long tzOffset = zone.getOffset(ctm);
+                            if (DBG) {
+                                log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
                                         TimeUtils.logTimeOfDay(ctm));
-                        }
-                        if (getAutoTime()) {
-                            long adj = ctm - tzOffset;
-                            if (DBG) log("pollStateDone: adj ltod=" + TimeUtils.logTimeOfDay(adj));
-                            setAndBroadcastNetworkSetTime(adj);
-                        } else {
-                            // Adjust the saved NITZ time to account for tzOffset.
-                            mSavedTime = mSavedTime - tzOffset;
+                            }
+                            if (getAutoTime()) {
+                                long adj = ctm - tzOffset;
+                                if (DBG) log("pollStateDone: adj ltod=" +
+                                        TimeUtils.logTimeOfDay(adj));
+                                setAndBroadcastNetworkSetTime(adj);
+                            } else {
+                                // Adjust the saved NITZ time to account for tzOffset.
+                                mSavedTime = mSavedTime - tzOffset;
+                            }
                         }
                         if (DBG) log("pollStateDone: using default TimeZone");
                     } else if (iso.equals("")){
@@ -948,7 +958,7 @@
                         if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
                     }
 
-                    mNeedFixZone = false;
+                    mNeedFixZoneAfterNitz = false;
 
                     if (zone != null) {
                         log("pollStateDone: zone != null zone.getID=" + zone.getID());
@@ -1440,7 +1450,7 @@
                 // so we don't know how to identify the DST rules yet.  Save
                 // the information and hope to fix it up later.
 
-                mNeedFixZone = true;
+                mNeedFixZoneAfterNitz = true;
                 mZoneOffset  = tzOffset;
                 mZoneDst     = dst != 0;
                 mZoneTime    = c.getTimeInMillis();
@@ -1696,7 +1706,7 @@
         pw.println(" mGsmRoaming=" + mGsmRoaming);
         pw.println(" mDataRoaming=" + mDataRoaming);
         pw.println(" mEmergencyOnly=" + mEmergencyOnly);
-        pw.println(" mNeedFixZone=" + mNeedFixZone);
+        pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
         pw.println(" mZoneOffset=" + mZoneOffset);
         pw.println(" mZoneDst=" + mZoneDst);
         pw.println(" mZoneTime=" + mZoneTime);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 414ae0d..0e75b80 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -210,28 +210,31 @@
             glEnableVertexAttribArray(attribTexCoords);
             checkGlError();
 
-            glUniform1i(uniformTexture, texture);
+            glUniform1i(uniformTexture, 0);
+            checkGlError();
+
+            // drawQuad
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+            glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+            checkGlError();
+
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+            glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+            checkGlError();
+
+            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
             checkGlError();
             
             while (!mFinished) {
                 checkCurrent();
 
-                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-                checkGlError();
-
                 glClear(GL_COLOR_BUFFER_BIT);
                 checkGlError();
 
-                // drawQuad
-                triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
-                glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
-                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
-                triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
-                glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
-                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+                checkGlError();
 
                 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
                     throw new RuntimeException("Cannot swap buffers");
diff --git a/tests/RenderScriptTests/Balls/Android.mk b/tests/RenderScriptTests/Balls/Android.mk
new file mode 100644
index 0000000..b109584
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsBalls
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Balls/AndroidManifest.xml b/tests/RenderScriptTests/Balls/AndroidManifest.xml
new file mode 100644
index 0000000..80e6b39
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.balls">
+    <uses-sdk android:minSdkVersion="14" />
+    <application 
+        android:label="RsBalls"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="Balls"
+                  android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/Balls/_index.html b/tests/RenderScriptTests/Balls/_index.html
new file mode 100644
index 0000000..8760485
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/_index.html
@@ -0,0 +1 @@
+<p>A brute force physics simulation that renders many balls onto the screen and moves them according to user touch and gravity.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/Balls/res/drawable/flares.png b/tests/RenderScriptTests/Balls/res/drawable/flares.png
new file mode 100644
index 0000000..3a5c970
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/res/drawable/flares.png
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png b/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
new file mode 100644
index 0000000..2c6558e
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class Balls extends Activity implements SensorEventListener {
+    //EventListener mListener = new EventListener();
+
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = false;
+
+    private BallsView mView;
+    private SensorManager mSensorManager;
+
+    // get the current looper (from your Activity UI thread for instance
+
+
+    public void onSensorChanged(SensorEvent event) {
+        //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
+        synchronized (this) {
+            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+                if(mView != null) {
+                    mView.setAccel(event.values[0], event.values[1], event.values[2]);
+                }
+            }
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new BallsView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        mSensorManager.registerListener(this,
+                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                                        SensorManager.SENSOR_DELAY_FASTEST);
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.pause();
+        onStop();
+    }
+
+    @Override
+    protected void onStop() {
+        mSensorManager.unregisterListener(this);
+        super.onStop();
+    }
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+
+
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
new file mode 100644
index 0000000..8cab9b8
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class BallsRS {
+    public static final int PART_COUNT = 900;
+
+    public BallsRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_balls mScript;
+    private ScriptC_ball_physics mPhysicsScript;
+    private ProgramFragment mPFLines;
+    private ProgramFragment mPFPoints;
+    private ProgramVertex mPV;
+    private ScriptField_Point mPoints;
+    private ScriptField_VpConsts mVpConsts;
+
+    void updateProjectionMatrices() {
+        mVpConsts = new ScriptField_VpConsts(mRS, 1,
+                                             Allocation.USAGE_SCRIPT |
+                                             Allocation.USAGE_GRAPHICS_CONSTANTS);
+        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+        Matrix4f mvp = new Matrix4f();
+        mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
+        i.MVP = mvp;
+        mVpConsts.set(i, 0, true);
+    }
+
+    private void createProgramVertex() {
+        updateProjectionMatrices();
+
+        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
+        String t =  "varying vec4 varColor;\n" +
+                    "void main() {\n" +
+                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
+                    "  pos.xy = ATTRIB_position;\n" +
+                    "  gl_Position = UNI_MVP * pos;\n" +
+                    "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
+                    "  gl_PointSize = ATTRIB_size;\n" +
+                    "}\n";
+        sb.setShader(t);
+        sb.addConstant(mVpConsts.getType());
+        sb.addInput(mPoints.getElement());
+        ProgramVertex pvs = sb.create();
+        pvs.bindConstants(mVpConsts.getAllocation(), 0);
+        mRS.bindProgramVertex(pvs);
+    }
+
+    private Allocation loadTexture(int id) {
+        final Allocation allocation =
+            Allocation.createFromBitmapResource(mRS, mRes,
+                id, Allocation.MipmapControl.MIPMAP_NONE,
+                Allocation.USAGE_GRAPHICS_TEXTURE);
+        return allocation;
+    }
+
+    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mRS = rs;
+        mRes = res;
+
+        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setPointSpriteTexCoordinateReplacement(true);
+        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        pfb.setVaryingColor(true);
+        mPFPoints = pfb.create();
+
+        pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setVaryingColor(true);
+        mPFLines = pfb.create();
+
+        android.util.Log.e("rs", "Load texture");
+        mPFPoints.bindTexture(loadTexture(R.drawable.flares), 0);
+
+        mPoints = new ScriptField_Point(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
+
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(mPoints.getAllocation());
+        smb.addIndexSetType(Mesh.Primitive.POINT);
+        Mesh smP = smb.create();
+
+        mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics);
+
+        mScript = new ScriptC_balls(mRS, mRes, R.raw.balls);
+        mScript.set_partMesh(smP);
+        mScript.set_physics_script(mPhysicsScript);
+        mScript.bind_point(mPoints);
+        mScript.bind_balls1(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+        mScript.bind_balls2(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+
+        mScript.set_gPFLines(mPFLines);
+        mScript.set_gPFPoints(mPFPoints);
+        createProgramVertex();
+
+        mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS));
+
+        mPhysicsScript.set_gMinPos(new Float2(5, 5));
+        mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
+
+        mScript.invoke_initParts(width, height);
+
+        mRS.bindRootScript(mScript);
+    }
+
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        mPhysicsScript.invoke_touch(x, y, pressure, id);
+    }
+
+    public void setAccel(float x, float y) {
+        mPhysicsScript.set_gGravityVector(new Float2(x, y));
+    }
+
+}
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
new file mode 100644
index 0000000..b3b3756
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BallsView extends RSSurfaceView {
+
+    public BallsView(Context context) {
+        super(context);
+        //setFocusable(true);
+    }
+
+    private RenderScriptGL mRS;
+    private BallsRS mRender;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
+            mRender = new BallsRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+        mRender.updateProjectionMatrices();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if(mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+            return false;
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+
+    void setAccel(float x, float y, float z) {
+        if (mRender == null) {
+            return;
+        }
+        mRender.setAccel(x, -y);
+    }
+
+}
+
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
new file mode 100644
index 0000000..8a3db6d
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
@@ -0,0 +1,146 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+
+#include "balls.rsh"
+
+float2 gGravityVector = {0.f, 9.8f};
+
+float2 gMinPos = {0.f, 0.f};
+float2 gMaxPos = {1280.f, 700.f};
+
+static float2 touchPos[10];
+static float touchPressure[10];
+
+void touch(float x, float y, float pressure, int id) {
+    if (id >= 10) {
+        return;
+    }
+
+    touchPos[id].x = x;
+    touchPos[id].y = y;
+    touchPressure[id] = pressure;
+}
+
+void root(const Ball_t *ballIn, Ball_t *ballOut, const BallControl_t *ctl, uint32_t x) {
+    float2 fv = {0, 0};
+    float2 pos = ballIn->position;
+
+    int arcID = -1;
+    float arcInvStr = 100000;
+
+    const Ball_t * bPtr = rsGetElementAt(ctl->ain, 0);
+    for (uint32_t xin = 0; xin < ctl->dimX; xin++) {
+        float2 vec = bPtr[xin].position - pos;
+        float2 vec2 = vec * vec;
+        float len2 = vec2.x + vec2.y;
+
+        if (len2 < 10000) {
+            //float minDist = ballIn->size + bPtr[xin].size;
+            float forceScale = ballIn->size * bPtr[xin].size;
+            forceScale *= forceScale;
+
+            if (len2 > 16 /* (minDist*minDist)*/)  {
+                // Repulsion
+                float len = sqrt(len2);
+                fv -= (vec / (len * len * len)) * 20000.f * forceScale;
+            } else {
+                if (len2 < 1) {
+                    if (xin == x) {
+                        continue;
+                    }
+                    ballOut->delta = 0.f;
+                    ballOut->position = ballIn->position;
+                    if (xin > x) {
+                        ballOut->position.x += 1.f;
+                    } else {
+                        ballOut->position.x -= 1.f;
+                    }
+                    //ballOut->color.rgb = 1.f;
+                    //ballOut->arcID = -1;
+                    //ballOut->arcStr = 0;
+                    continue;
+                }
+                // Collision
+                float2 axis = normalize(vec);
+                float e1 = dot(axis, ballIn->delta);
+                float e2 = dot(axis, bPtr[xin].delta);
+                float e = (e1 - e2) * 0.45f;
+                if (e1 > 0) {
+                    fv -= axis * e;
+                } else {
+                    fv += axis * e;
+                }
+            }
+        }
+    }
+
+    fv /= ballIn->size * ballIn->size * ballIn->size;
+    fv -= gGravityVector * 4.f;
+    fv *= ctl->dt;
+
+    for (int i=0; i < 10; i++) {
+        if (touchPressure[i] > 0.1f) {
+            float2 vec = touchPos[i] - ballIn->position;
+            float2 vec2 = vec * vec;
+            float len2 = max(2.f, vec2.x + vec2.y);
+            fv -= (vec / len2) * touchPressure[i] * 300.f;
+        }
+    }
+
+    ballOut->delta = (ballIn->delta * (1.f - 0.004f)) + fv;
+    ballOut->position = ballIn->position + (ballOut->delta * ctl->dt);
+
+    const float wallForce = 400.f;
+    if (ballOut->position.x > (gMaxPos.x - 20.f)) {
+        float d = gMaxPos.x - ballOut->position.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x > 0) {
+                ballOut->delta.x *= -0.7f;
+            }
+            ballOut->position.x = gMaxPos.x;
+        } else {
+            ballOut->delta.x -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.x < (gMinPos.x + 20.f)) {
+        float d = ballOut->position.x - gMinPos.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x < 0) {
+                ballOut->delta.x *= -0.7f;
+            }
+            ballOut->position.x = gMinPos.x + 1.f;
+        } else {
+            ballOut->delta.x += min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y > (gMaxPos.y - 20.f)) {
+        float d = gMaxPos.y - ballOut->position.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y > 0) {
+                ballOut->delta.y *= -0.7f;
+            }
+            ballOut->position.y = gMaxPos.y;
+        } else {
+            ballOut->delta.y -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y < (gMinPos.y + 20.f)) {
+        float d = ballOut->position.y - gMinPos.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y < 0) {
+                ballOut->delta.y *= -0.7f;
+            }
+            ballOut->position.y = gMinPos.y + 1.f;
+        } else {
+            ballOut->delta.y += min(wallForce / (d * d * d), 10.f);
+        }
+    }
+
+    ballOut->size = ballIn->size;
+
+    //rsDebug("physics pos out", ballOut->position);
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
new file mode 100644
index 0000000..dcdd586
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
@@ -0,0 +1,83 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+#include "rs_graphics.rsh"
+
+#include "balls.rsh"
+
+#pragma stateVertex(parent)
+#pragma stateStore(parent)
+
+rs_program_fragment gPFPoints;
+rs_program_fragment gPFLines;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 position;
+    float size;
+} Point_t;
+Point_t *point;
+
+typedef struct VpConsts {
+    rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+rs_script physics_script;
+
+Ball_t *balls1;
+Ball_t *balls2;
+
+static int frame = 0;
+
+void initParts(int w, int h)
+{
+    uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls1));
+
+    for (uint32_t ct=0; ct < dimX; ct++) {
+        balls1[ct].position.x = rsRand(0.f, (float)w);
+        balls1[ct].position.y = rsRand(0.f, (float)h);
+        balls1[ct].delta.x = 0.f;
+        balls1[ct].delta.y = 0.f;
+        balls1[ct].size = 1.f;
+
+        float r = rsRand(100.f);
+        if (r > 90.f) {
+            balls1[ct].size += pow(10.f, rsRand(0.f, 2.f)) * 0.07f;
+        }
+    }
+}
+
+
+
+int root() {
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+
+    BallControl_t bc;
+    Ball_t *bout;
+
+    if (frame & 1) {
+        bc.ain = rsGetAllocation(balls2);
+        bc.aout = rsGetAllocation(balls1);
+        bout = balls1;
+    } else {
+        bc.ain = rsGetAllocation(balls1);
+        bc.aout = rsGetAllocation(balls2);
+        bout = balls2;
+    }
+
+    bc.dimX = rsAllocationGetDimX(bc.ain);
+    bc.dt = 1.f / 30.f;
+
+    rsForEach(physics_script, bc.ain, bc.aout, &bc, sizeof(bc));
+
+    for (uint32_t ct=0; ct < bc.dimX; ct++) {
+        point[ct].position = bout[ct].position;
+        point[ct].size = 6.f /*+ bout[ct].color.g * 6.f*/ * bout[ct].size;
+    }
+
+    frame++;
+    rsgBindProgramFragment(gPFPoints);
+    rsgDrawMesh(partMesh);
+    return 1;
+}
+
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
new file mode 100644
index 0000000..fc886f9
--- /dev/null
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
@@ -0,0 +1,18 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+    float2 delta;
+    float2 position;
+    //float3 color;
+    float size;
+    //int arcID;
+    //float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+    uint32_t dimX;
+    rs_allocation ain;
+    rs_allocation aout;
+    float dt;
+} BallControl_t;
diff --git a/tests/RenderScriptTests/Fountain/Android.mk b/tests/RenderScriptTests/Fountain/Android.mk
new file mode 100644
index 0000000..2049ecf
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+# TODO: build fails with this set
+# LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := RsFountain
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Fountain/AndroidManifest.xml b/tests/RenderScriptTests/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..d19b8c3
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.fountain">
+    <uses-sdk android:minSdkVersion="14" />
+    <application
+        android:label="RsFountain"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="Fountain">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/Fountain/_index.html b/tests/RenderScriptTests/Fountain/_index.html
new file mode 100644
index 0000000..223242f
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/_index.html
@@ -0,0 +1,5 @@
+<p>An example that renders many dots on the screen that follow a user's touch. The dots fall 
+to the bottom of the screen when the user releases the finger.</p>
+
+
+
diff --git a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
new file mode 100644
index 0000000..311455a
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountain;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Fountain extends Activity {
+    //EventListener mListener = new EventListener();
+
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = false;
+
+    private FountainView mView;
+
+    // get the current looper (from your Activity UI thread for instance
+
+
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new FountainView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        Log.e("rs", "onResume");
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        Log.e("rs", "onPause");
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.pause();
+
+
+
+        //Runtime.getRuntime().exit(0);
+    }
+
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+
+
+}
+
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
new file mode 100644
index 0000000..646c807
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountain;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+
+public class FountainRS {
+    public static final int PART_COUNT = 50000;
+
+    public FountainRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_fountain mScript;
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+
+        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setVaryingColor(true);
+        rs.bindProgramFragment(pfb.create());
+
+        ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);//
+ //                                                        Allocation.USAGE_GRAPHICS_VERTEX);
+
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(points.getAllocation());
+        smb.addIndexSetType(Mesh.Primitive.POINT);
+        Mesh sm = smb.create();
+
+        mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
+        mScript.set_partMesh(sm);
+        mScript.bind_point(points);
+        mRS.bindRootScript(mScript);
+    }
+
+    boolean holdingColor[] = new boolean[10];
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        if (id >= holdingColor.length) {
+            return;
+        }
+        int rate = (int)(pressure * pressure * 500.f);
+        if (rate > 500) {
+            rate = 500;
+        }
+        if (rate > 0) {
+            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+            holdingColor[id] = true;
+        } else {
+            holdingColor[id] = false;
+        }
+
+    }
+}
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
new file mode 100644
index 0000000..ba09421
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSTextureView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FountainView extends RSTextureView {
+
+    public FountainView(Context context) {
+        super(context);
+        //setFocusable(true);
+    }
+
+    private RenderScriptGL mRS;
+    private FountainRS mRender;
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        android.util.Log.e("rs", "onAttachedToWindow");
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRender = new FountainRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        android.util.Log.e("rs", "onDetachedFromWindow");
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
new file mode 100644
index 0000000..151b689
--- /dev/null
+++ b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
@@ -0,0 +1,70 @@
+// Fountain test script
+#pragma version(1)
+#pragma rs_fp_relaxed
+
+#pragma rs java_package_name(com.example.android.rs.fountain)
+
+#pragma stateFragment(parent)
+
+#include "rs_graphics.rsh"
+
+static int newPart = 0;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 delta;
+    float2 position;
+    uchar4 color;
+} Point_t;
+Point_t *point;
+
+int root() {
+    float dt = min(rsGetDt(), 0.1f);
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+    const float height = rsgGetHeight();
+    const int size = rsAllocationGetDimX(rsGetAllocation(point));
+    float dy2 = dt * (10.f);
+    Point_t * p = point;
+    for (int ct=0; ct < size; ct++) {
+        p->delta.y += dy2;
+        p->position += p->delta;
+        if ((p->position.y > height) && (p->delta.y > 0)) {
+            p->delta.y *= -0.3f;
+        }
+        p++;
+    }
+
+    rsgDrawMesh(partMesh);
+    return 1;
+}
+
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
+{
+    if (newColor) {
+        partColor[index].x = rsRand(0.5f, 1.0f);
+        partColor[index].y = rsRand(1.0f);
+        partColor[index].z = rsRand(1.0f);
+    }
+    float rMax = ((float)rate) * 0.02f;
+    int size = rsAllocationGetDimX(rsGetAllocation(point));
+    uchar4 c = rsPackColorTo8888(partColor[index]);
+
+    Point_t * np = &point[newPart];
+    float2 p = {x, y};
+    while (rate--) {
+        float angle = rsRand(3.14f * 2.f);
+        float len = rsRand(rMax);
+        np->delta.x = len * sin(angle);
+        np->delta.y = len * cos(angle);
+        np->position = p;
+        np->color = c;
+        newPart++;
+        np++;
+        if (newPart >= size) {
+            newPart = 0;
+            np = &point[newPart];
+        }
+    }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
new file mode 100644
index 0000000..55a4fd8
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+# TODO: build fails with this set
+# LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := RsFountainFbo
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
new file mode 100644
index 0000000..082744b
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.fountainfbo">
+    <uses-sdk android:minSdkVersion="14" />
+    <application
+        android:label="RsFountainFbo"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="FountainFbo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/FountainFbo/_index.html b/tests/RenderScriptTests/FountainFbo/_index.html
new file mode 100644
index 0000000..5508657
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/_index.html
@@ -0,0 +1,7 @@
+<p>An example that renders many dots on the screen that follow a user's touch. The dots fall 
+to the bottom of the screen when no touch is detected. This example modifies
+the <a href="../Fountain/index.html">Fountain</a> sample to include rendering to a
+a framebuffer object as well as the default framebuffer.</p>
+
+
+
diff --git a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
new file mode 100644
index 0000000..d8ba30fd
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountainfbo;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class FountainFbo extends Activity {
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = false;
+
+    private FountainFboView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        /* Create our Preview view and set it as the content of our Activity */
+        mView = new FountainFboView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        Log.e("rs", "onResume");
+
+        /* Ideally a game should implement onResume() and onPause()
+         to take appropriate action when the activity loses focus */
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        Log.e("rs", "onPause");
+
+        /* Ideally a game should implement onResume() and onPause()
+        to take appropriate action when the activity loses focus */
+        super.onPause();
+        mView.pause();
+    }
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
new file mode 100644
index 0000000..3bf3ff1
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountainfbo;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramFragmentFixedFunction;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type;
+
+public class FountainFboRS {
+    public static final int PART_COUNT = 50000;
+
+    public FountainFboRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_fountainfbo mScript;
+    private Allocation mColorBuffer;
+    private ProgramFragment mProgramFragment;
+    private ProgramFragment mTextureProgramFragment;
+    public void init(RenderScriptGL rs, Resources res) {
+      mRS = rs;
+      mRes = res;
+
+      ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
+
+      Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+      smb.addVertexAllocation(points.getAllocation());
+      smb.addIndexSetType(Mesh.Primitive.POINT);
+      Mesh sm = smb.create();
+
+      mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);
+      mScript.set_partMesh(sm);
+      mScript.bind_point(points);
+
+      ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+      pfb.setVaryingColor(true);
+      mProgramFragment = pfb.create();
+      mScript.set_gProgramFragment(mProgramFragment);
+
+      /* Second fragment shader to use a texture (framebuffer object) to draw with */
+      pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+          ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+
+      /* Set the fragment shader in the Renderscript runtime */
+      mTextureProgramFragment = pfb.create();
+      mScript.set_gTextureProgramFragment(mTextureProgramFragment);
+
+      /* Create the allocation for the color buffer */
+      Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));
+      colorBuilder.setX(256).setY(256);
+      mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),
+      Allocation.USAGE_GRAPHICS_TEXTURE |
+      Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+
+      /* Set the allocation in the Renderscript runtime */
+      mScript.set_gColorBuffer(mColorBuffer);
+
+      mRS.bindRootScript(mScript);
+  }
+
+    boolean holdingColor[] = new boolean[10];
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        if (id >= holdingColor.length) {
+            return;
+        }
+        int rate = (int)(pressure * pressure * 500.f);
+        if (rate > 500) {
+            rate = 500;
+        }
+        if (rate > 0) {
+            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+            holdingColor[id] = true;
+        } else {
+            holdingColor[id] = false;
+        }
+
+    }
+}
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
new file mode 100644
index 0000000..6e40da3
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.fountainfbo;
+
+
+import android.renderscript.RSTextureView;
+import android.renderscript.RenderScriptGL;
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class FountainFboView extends RSTextureView {
+
+    public FountainFboView(Context context) {
+        super(context);
+    }
+
+    private RenderScriptGL mRS;
+    private FountainFboRS mRender;
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        android.util.Log.e("rs", "onAttachedToWindow");
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRender = new FountainFboRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        android.util.Log.e("rs", "onDetachedFromWindow");
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
new file mode 100644
index 0000000..763f6ba
--- /dev/null
+++ b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
@@ -0,0 +1,106 @@
+// Fountain test script
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.fountainfbo)
+
+#pragma stateFragment(parent)
+
+#include "rs_graphics.rsh"
+
+static int newPart = 0;
+rs_mesh partMesh;
+rs_program_vertex gProgramVertex;
+
+//allocation for color buffer
+rs_allocation gColorBuffer;
+//fragment shader for rendering without a texture (used for rendering to framebuffer object)
+rs_program_fragment gProgramFragment;
+//fragment shader for rendering with a texture (used for rendering to default framebuffer)
+rs_program_fragment gTextureProgramFragment;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 delta;
+    float2 position;
+    uchar4 color;
+} Point_t;
+Point_t *point;
+
+int root() {
+    float dt = min(rsGetDt(), 0.1f);
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+    const float height = rsgGetHeight();
+    const int size = rsAllocationGetDimX(rsGetAllocation(point));
+    float dy2 = dt * (10.f);
+    Point_t * p = point;
+    for (int ct=0; ct < size; ct++) {
+        p->delta.y += dy2;
+        p->position += p->delta;
+        if ((p->position.y > height) && (p->delta.y > 0)) {
+            p->delta.y *= -0.3f;
+        }
+        p++;
+    }
+    //Tell Renderscript runtime to render to the frame buffer object
+    rsgBindColorTarget(gColorBuffer, 0);
+
+    //Begin rendering on a white background
+    rsgClearColor(1.f, 1.f, 1.f, 1.f);
+    rsgDrawMesh(partMesh);
+
+    //When done, tell Renderscript runtime to stop rendering to framebuffer object
+    rsgClearAllRenderTargets();
+
+    //Bind a new fragment shader that declares the framebuffer object to be used as a texture
+    rsgBindProgramFragment(gTextureProgramFragment);
+
+    //Bind the framebuffer object to the fragment shader at slot 0 as a texture
+    rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);
+
+    //Draw a quad using the framebuffer object as the texture
+    float startX = 10, startY = 10;
+    float s = 256;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
+                         startX, startY + s, 0, 0, 0,
+                         startX + s, startY + s, 0, 1, 0,
+                         startX + s, startY, 0, 1, 1);
+
+    //Rebind the original fragment shader to render as normal
+    rsgBindProgramFragment(gProgramFragment);
+
+    //Render the main scene
+    rsgDrawMesh(partMesh);
+
+    return 1;
+}
+
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
+{
+    if (newColor) {
+        partColor[index].x = rsRand(0.5f, 1.0f);
+        partColor[index].y = rsRand(1.0f);
+        partColor[index].z = rsRand(1.0f);
+    }
+    float rMax = ((float)rate) * 0.02f;
+    int size = rsAllocationGetDimX(rsGetAllocation(point));
+    uchar4 c = rsPackColorTo8888(partColor[index]);
+
+    Point_t * np = &point[newPart];
+    float2 p = {x, y};
+    while (rate--) {
+        float angle = rsRand(3.14f * 2.f);
+        float len = rsRand(rMax);
+        np->delta.x = len * sin(angle);
+        np->delta.y = len * cos(angle);
+        np->position = p;
+        np->color = c;
+        newPart++;
+        np++;
+        if (newPart >= size) {
+            newPart = 0;
+            np = &point[newPart];
+        }
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/Android.mk b/tests/RenderScriptTests/HelloWorld/Android.mk
new file mode 100644
index 0000000..2af1cdb
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsHelloWorld
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
new file mode 100644
index 0000000..1d37dc9
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+ 
+          http://www.apache.org/licenses/LICENSE-2.0
+ 
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.helloworld">
+    <uses-sdk android:minSdkVersion="11" />
+    <application android:label="RsHelloWorld"
+    android:icon="@drawable/test_pattern">
+        <activity android:name="HelloWorld"
+                  android:label="RsHelloWorld"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/HelloWorld/_index.html b/tests/RenderScriptTests/HelloWorld/_index.html
new file mode 100644
index 0000000..4cab738
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/_index.html
@@ -0,0 +1 @@
+<p>A Renderscript graphics application that draws the text "Hello, World!" where the user touches.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
new file mode 100644
index 0000000..9b1697b
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// Renderscript activity
+public class HelloWorld extends Activity {
+
+    // Custom view to use with RenderScript
+    private HelloWorldView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our view and set it as the content of our Activity
+        mView = new HelloWorldView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally an app should implement onResume() and onPause()
+        // to take appropriate action when the activity loses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally an app should implement onResume() and onPause()
+        // to take appropriate action when the activity loses focus
+        super.onPause();
+        mView.pause();
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
new file mode 100644
index 0000000..4316411
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+// This is the renderer for the HelloWorldView
+public class HelloWorldRS {
+    private Resources mRes;
+    private RenderScriptGL mRS;
+
+    private ScriptC_helloworld mScript;
+
+    public HelloWorldRS() {
+    }
+
+    // This provides us with the renderscript context and resources that
+    // allow us to create the script that does rendering
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+        initRS();
+    }
+
+    public void onActionDown(int x, int y) {
+        mScript.set_gTouchX(x);
+        mScript.set_gTouchY(y);
+    }
+
+    private void initRS() {
+        mScript = new ScriptC_helloworld(mRS, mRes, R.raw.helloworld);
+        mRS.bindRootScript(mScript);
+    }
+}
+
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
new file mode 100644
index 0000000..557ebc5
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.helloworld;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class HelloWorldView extends RSSurfaceView {
+    // Renderscipt context
+    private RenderScriptGL mRS;
+    // Script that does the rendering
+    private HelloWorldRS mRender;
+
+    public HelloWorldView(Context context) {
+        super(context);
+        ensureRenderScript();
+    }
+
+    private void ensureRenderScript() {
+        if (mRS == null) {
+            // Initialize renderscript with desired surface characteristics.
+            // In this case, just use the defaults
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            // Create an instance of the script that does the rendering
+            mRender = new HelloWorldRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ensureRenderScript();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        // Handle the system event and clean up
+        mRender = null;
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        // Pass touch events from the system to the rendering script
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+            return true;
+        }
+
+        return false;
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
new file mode 100644
index 0000000..bcf624e
--- /dev/null
+++ b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
@@ -0,0 +1,47 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+// Tell which java package name the reflected files should belong to
+#pragma rs java_package_name(com.example.android.rs.helloworld)
+
+// Built-in header with graphics API's
+#include "rs_graphics.rsh"
+
+// gTouchX and gTouchY are variables that will be reflected for use
+// by the java API. We can use them to notify the script of touch events.
+int gTouchX;
+int gTouchY;
+
+// This is invoked automatically when the script is created
+void init() {
+    gTouchX = 50.0f;
+    gTouchY = 50.0f;
+}
+
+int root(void) {
+
+    // Clear the background color
+    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    // Tell the runtime what the font color should be
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    // Introuduce ourselves to the world by drawing a greeting
+    // at the position user touched on the screen
+    rsgDrawText("Hello World!", gTouchX, gTouchY);
+
+    // Return value tells RS roughly how often to redraw
+    // in this case 20 ms
+    return 20;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/Android.mk b/tests/RenderScriptTests/MiscSamples/Android.mk
new file mode 100644
index 0000000..6b8b691
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsMiscSamples
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
new file mode 100644
index 0000000..08a3976
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.miscsamples">
+    <uses-sdk android:minSdkVersion="11" />
+    <application android:label="RsMiscSamples"
+    android:icon="@drawable/test_pattern">
+        <activity android:name="RsList"
+                  android:label="RsList"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name="RsRenderStates"
+                  android:label="RsStates"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/MiscSamples/_index.html b/tests/RenderScriptTests/MiscSamples/_index.html
new file mode 100644
index 0000000..5872431
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/_index.html
@@ -0,0 +1 @@
+<p>A set of samples that demonstrate how to use various features of the Renderscript APIs.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
new file mode 100644
index 0000000..b631e1e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
new file mode 100644
index 0000000..baf35d0
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
new file mode 100644
index 0000000..8e34714
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
new file mode 100644
index 0000000..3cd3775
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
new file mode 100644
index 0000000..1e08f3b
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
new file mode 100644
index 0000000..e492a47
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba;
+   lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba;
+   lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba;
+   col0.xyz = col0.xyz*col1.xyz*1.5;
+   col0.xyz = mix(col0.xyz, col2.xyz, col2.w);
+   col0.w = 0.5;
+   gl_FragColor = col0;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
new file mode 100644
index 0000000..5fc05f1
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(-varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos);
+   vec3 light0R = -reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+   float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
new file mode 100644
index 0000000..a2c807e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
@@ -0,0 +1,21 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec3 oldPos = objPos.xyz;
+   objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time);
+   objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5);
+   objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75);
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz);
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
new file mode 100644
index 0000000..e6885a3
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
new file mode 100644
index 0000000..238ecad
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
@@ -0,0 +1,16 @@
+
+varying lowp float light0_Diffuse;
+varying lowp float light0_Specular;
+varying lowp float light1_Diffuse;
+varying lowp float light1_Specular;
+varying vec2 varTex0;
+
+void main() {
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_light_DiffuseColor[0].xyz + light1_Diffuse * UNI_light_DiffuseColor[1].xyz);
+   col.xyz += light0_Specular * UNI_light_SpecularColor[0].xyz;
+   col.xyz += light1_Specular * UNI_light_SpecularColor[1].xyz;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
new file mode 100644
index 0000000..7a1310a
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
@@ -0,0 +1,32 @@
+varying float light0_Diffuse;
+varying float light0_Specular;
+varying float light1_Diffuse;
+varying float light1_Specular;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 worldPos = UNI_model[0] * ATTRIB_position;
+   worldPos = UNI_model[1] * worldPos;
+   gl_Position = UNI_proj * worldPos;
+
+   mat4 model0 = UNI_model[0];
+   mat3 model3 = mat3(model0[0].xyz, model0[1].xyz, model0[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+   vec3 V = normalize(-worldPos.xyz);
+
+   vec3 light0Vec = normalize(UNI_light_Posision[0].xyz - worldPos.xyz);
+   vec3 light0R = -reflect(light0Vec, worldNorm);
+   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light_Diffuse[0];
+   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+   light0_Specular = pow(light0Spec, UNI_light_CosinePower[0]) * UNI_light_Specular[0];
+
+   vec3 light1Vec = normalize(UNI_light_Posision[1].xyz - worldPos.xyz);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light_Diffuse[1];
+   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+   light1_Specular = pow(light1Spec, UNI_light_CosinePower[1]) * UNI_light_Specular[1];
+
+   gl_PointSize = 1.0;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
new file mode 100644
index 0000000..15696a4
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
@@ -0,0 +1,8 @@
+
+varying vec3 worldNormal;
+
+void main() {
+   lowp vec4 col = textureCube(UNI_Tex0, worldNormal);
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
new file mode 100644
index 0000000..70f5cd6
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
@@ -0,0 +1,10 @@
+varying vec3 worldNormal;
+
+// This is where actual shader code begins
+void main() {
+   vec4 worldPos = UNI_model * ATTRIB_position;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   worldNormal = model3 * ATTRIB_normal;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
new file mode 100644
index 0000000..d56e203
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
@@ -0,0 +1,16 @@
+
+varying lowp float light0_Diffuse;
+varying lowp float light0_Specular;
+varying lowp float light1_Diffuse;
+varying lowp float light1_Specular;
+varying vec2 varTex0;
+
+void main() {
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
new file mode 100644
index 0000000..f7d01de
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
@@ -0,0 +1,30 @@
+varying float light0_Diffuse;
+varying float light0_Specular;
+varying float light1_Diffuse;
+varying float light1_Specular;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 worldPos = UNI_model * ATTRIB_position;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+   vec3 V = normalize(-worldPos.xyz);
+
+   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz);
+   vec3 light0R = -reflect(light0Vec, worldNorm);
+   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+   light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+   light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+   gl_PointSize = 1.0;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
new file mode 100644
index 0000000..0322b01
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
new file mode 100644
index 0000000..dade3b3
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RsList extends Activity {
+
+    private RsListView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new RsListView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity loses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity loses focus
+        super.onPause();
+        mView.pause();
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
new file mode 100644
index 0000000..eeb2480
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+
+import java.io.Writer;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+
+public class RsListRS {
+
+    private final int STATE_LAST_FOCUS = 1;
+
+    private static final String[] DATA_LIST = {
+    "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+    "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+    "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+    "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+    "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+    "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+    "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+    "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+    "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+    "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+    "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+    "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+    "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+    "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+    "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+    "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+    "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+    "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+    "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+    "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+    "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+    "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+    "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+    "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+    "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+    "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+    "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+    "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+    "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+    "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+    "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+    "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+    "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+    "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+    "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+    "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+    "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+    "Ukraine", "United Arab Emirates", "United Kingdom",
+    "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+    "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+    "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+    };
+
+    public RsListRS() {
+    }
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+        initRS();
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private Font mItalic;
+
+    ScriptField_ListAllocs_s mListAllocs;
+
+    private ScriptC_rslist mScript;
+
+    int mLastX;
+    int mLastY;
+
+    public void onActionDown(int x, int y) {
+        mScript.set_gDY(0.0f);
+
+        mLastX = x;
+        mLastY = y;
+    }
+
+    public void onActionMove(int x, int y) {
+        int dx = mLastX - x;
+        int dy = mLastY - y;
+
+        if (Math.abs(dy) <= 2) {
+            dy = 0;
+        }
+
+        mScript.set_gDY(dy);
+
+        mLastX = x;
+        mLastY = y;
+    }
+
+    private void initRS() {
+
+        mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
+
+        mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length);
+        for (int i = 0; i < DATA_LIST.length; i ++) {
+            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
+            listElem.text = Allocation.createFromString(mRS, DATA_LIST[i], Allocation.USAGE_SCRIPT);
+            mListAllocs.set(listElem, i, false);
+        }
+
+        mListAllocs.copyAll();
+
+        mScript.bind_gList(mListAllocs);
+
+        mItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
+        mScript.set_gItalic(mItalic);
+
+        mRS.bindRootScript(mScript);
+    }
+}
+
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
new file mode 100644
index 0000000..db6e6c5
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class RsListView extends RSSurfaceView {
+
+    public RsListView(Context context) {
+        super(context);
+        ensureRenderScript();
+    }
+
+    private RenderScriptGL mRS;
+    private RsListRS mRender;
+
+    private void ensureRenderScript() {
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRender = new RsListRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ensureRenderScript();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mRender = null;
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        boolean ret = false;
+        int act = ev.getAction();
+        if (act == MotionEvent.ACTION_DOWN) {
+            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+            ret = true;
+        } else if (act == MotionEvent.ACTION_MOVE) {
+            mRender.onActionMove((int)ev.getX(), (int)ev.getY());
+            ret = true;
+        }
+
+        return ret;
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
new file mode 100644
index 0000000..f4ea76e
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class RsRenderStates extends Activity {
+
+    private RsRenderStatesView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new RsRenderStatesView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.pause();
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
new file mode 100644
index 0000000..0e319fe
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.renderscript.*;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.Sampler.Value;
+import android.util.Log;
+
+
+public class RsRenderStatesRS {
+
+    int mWidth;
+    int mHeight;
+
+    public RsRenderStatesRS() {
+    }
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mWidth = mRS.getWidth();
+        mHeight = mRS.getHeight();
+        mRes = res;
+        mOptionsARGB.inScaled = false;
+        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        mMode = 0;
+        mMaxModes = 0;
+        initRS();
+    }
+
+    public void surfaceChanged() {
+        mWidth = mRS.getWidth();
+        mHeight = mRS.getHeight();
+
+        Matrix4f proj = new Matrix4f();
+        proj.loadOrthoWindow(mWidth, mHeight);
+        mPVA.setProjection(proj);
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+
+    private Sampler mLinearClamp;
+    private Sampler mLinearWrap;
+    private Sampler mMipLinearWrap;
+    private Sampler mNearestClamp;
+    private Sampler mMipLinearAniso8;
+    private Sampler mMipLinearAniso15;
+
+    private ProgramStore mProgStoreBlendNoneDepth;
+    private ProgramStore mProgStoreBlendNone;
+    private ProgramStore mProgStoreBlendAlpha;
+    private ProgramStore mProgStoreBlendAdd;
+
+    private ProgramFragment mProgFragmentTexture;
+    private ProgramFragment mProgFragmentColor;
+
+    private ProgramVertex mProgVertex;
+    private ProgramVertexFixedFunction.Constants mPVA;
+
+    // Custom shaders
+    private ProgramVertex mProgVertexCustom;
+    private ProgramFragment mProgFragmentCustom;
+    private ProgramFragment mProgFragmentMultitex;
+    private ScriptField_VertexShaderConstants_s mVSConst;
+    private ScriptField_VertexShaderConstants2_s mVSConst2;
+    private ScriptField_FragentShaderConstants_s mFSConst;
+    private ScriptField_FragentShaderConstants2_s mFSConst2;
+
+    private ProgramVertex mProgVertexCustom2;
+    private ProgramFragment mProgFragmentCustom2;
+
+    private ProgramVertex mProgVertexCube;
+    private ProgramFragment mProgFragmentCube;
+
+    private ProgramRaster mCullBack;
+    private ProgramRaster mCullFront;
+    private ProgramRaster mCullNone;
+
+    private Allocation mTexTorus;
+    private Allocation mTexOpaque;
+    private Allocation mTexTransparent;
+    private Allocation mTexChecker;
+    private Allocation mTexCube;
+
+    private Mesh mMbyNMesh;
+    private Mesh mTorus;
+
+    Font mFontSans;
+    Font mFontSerif;
+    Font mFontSerifBold;
+    Font mFontSerifItalic;
+    Font mFontSerifBoldItalic;
+    Font mFontMono;
+    private Allocation mTextAlloc;
+
+    private ScriptC_rsrenderstates mScript;
+
+    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+    int mMode;
+    int mMaxModes;
+
+    public void onActionDown(int x, int y) {
+        mMode ++;
+        mMode = mMode % mMaxModes;
+        mScript.set_gDisplayMode(mMode);
+    }
+
+    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) {
+
+        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+                                           2, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+        for (int y = 0; y <= hResolution; y++) {
+            final float normalizedY = (float)y / hResolution;
+            final float yOffset = (normalizedY - 0.5f) * height;
+            for (int x = 0; x <= wResolution; x++) {
+                float normalizedX = (float)x / wResolution;
+                float xOffset = (normalizedX - 0.5f) * width;
+                tmb.setTexture(normalizedX, normalizedY);
+                tmb.addVertex(xOffset, yOffset);
+             }
+        }
+
+        for (int y = 0; y < hResolution; y++) {
+            final int curY = y * (wResolution + 1);
+            final int belowY = (y + 1) * (wResolution + 1);
+            for (int x = 0; x < wResolution; x++) {
+                int curV = curY + x;
+                int belowV = belowY + x;
+                tmb.addTriangle(curV, belowV, curV + 1);
+                tmb.addTriangle(belowV, belowV + 1, curV + 1);
+            }
+        }
+
+        return tmb.create(true);
+    }
+
+    private void initProgramStore() {
+        // Use stock the stock program store object
+        mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS);
+        mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS);
+
+        // Create a custom program store
+        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+                             ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        mProgStoreBlendAlpha = builder.create();
+
+        mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS);
+
+        mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+        mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
+        mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
+        mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
+    }
+
+    private void initProgramFragment() {
+
+        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
+        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        mProgFragmentTexture = texBuilder.create();
+        mProgFragmentTexture.bindSampler(mLinearClamp, 0);
+
+        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
+        colBuilder.setVaryingColor(false);
+        mProgFragmentColor = colBuilder.create();
+
+        mScript.set_gProgFragmentColor(mProgFragmentColor);
+        mScript.set_gProgFragmentTexture(mProgFragmentTexture);
+    }
+
+    private void initProgramVertex() {
+        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+        mProgVertex = pvb.create();
+
+        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
+        ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
+        Matrix4f proj = new Matrix4f();
+        proj.loadOrthoWindow(mWidth, mHeight);
+        mPVA.setProjection(proj);
+
+        mScript.set_gProgVertex(mProgVertex);
+    }
+
+    private void initCustomShaders() {
+        mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
+        mVSConst2 = new ScriptField_VertexShaderConstants2_s(mRS, 1);
+        mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
+        mFSConst2 = new ScriptField_FragentShaderConstants2_s(mRS, 1);
+
+        mScript.bind_gVSConstants(mVSConst);
+        mScript.bind_gVSConstants2(mVSConst2);
+        mScript.bind_gFSConstants(mFSConst);
+        mScript.bind_gFSConstants2(mFSConst2);
+
+        // Initialize the shader builder
+        ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
+        // Specify the resource that contains the shader string
+        pvbCustom.setShader(mRes, R.raw.shaderv);
+        // Use a script field to spcify the input layout
+        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+        // Define the constant input layout
+        pvbCustom.addConstant(mVSConst.getAllocation().getType());
+        mProgVertexCustom = pvbCustom.create();
+        // Bind the source of constant data
+        mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0);
+
+        ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS);
+        // Specify the resource that contains the shader string
+        pfbCustom.setShader(mRes, R.raw.shaderf);
+        //Tell the builder how many textures we have
+        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+        // Define the constant input layout
+        pfbCustom.addConstant(mFSConst.getAllocation().getType());
+        mProgFragmentCustom = pfbCustom.create();
+        // Bind the source of constant data
+        mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0);
+
+        pvbCustom = new ProgramVertex.Builder(mRS);
+        pvbCustom.setShader(mRes, R.raw.shaderarrayv);
+        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+        pvbCustom.addConstant(mVSConst2.getAllocation().getType());
+        mProgVertexCustom2 = pvbCustom.create();
+        mProgVertexCustom2.bindConstants(mVSConst2.getAllocation(), 0);
+
+        pfbCustom = new ProgramFragment.Builder(mRS);
+        pfbCustom.setShader(mRes, R.raw.shaderarrayf);
+        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+        pfbCustom.addConstant(mFSConst2.getAllocation().getType());
+        mProgFragmentCustom2 = pfbCustom.create();
+        mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0);
+
+        // Cubemap test shaders
+        pvbCustom = new ProgramVertex.Builder(mRS);
+        pvbCustom.setShader(mRes, R.raw.shadercubev);
+        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
+        pvbCustom.addConstant(mVSConst.getAllocation().getType());
+        mProgVertexCube = pvbCustom.create();
+        mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0);
+
+        pfbCustom = new ProgramFragment.Builder(mRS);
+        pfbCustom.setShader(mRes, R.raw.shadercubef);
+        pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE);
+        mProgFragmentCube = pfbCustom.create();
+
+        pfbCustom = new ProgramFragment.Builder(mRS);
+        pfbCustom.setShader(mRes, R.raw.multitexf);
+        for (int texCount = 0; texCount < 3; texCount ++) {
+            pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+        }
+        mProgFragmentMultitex = pfbCustom.create();
+
+        mScript.set_gProgVertexCustom(mProgVertexCustom);
+        mScript.set_gProgFragmentCustom(mProgFragmentCustom);
+        mScript.set_gProgVertexCustom2(mProgVertexCustom2);
+        mScript.set_gProgFragmentCustom2(mProgFragmentCustom2);
+        mScript.set_gProgVertexCube(mProgVertexCube);
+        mScript.set_gProgFragmentCube(mProgFragmentCube);
+        mScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
+    }
+
+    private Allocation loadTextureRGB(int id) {
+        return Allocation.createFromBitmapResource(mRS, mRes, id,
+                                                   Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                   Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    private Allocation loadTextureARGB(int id) {
+        Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB);
+        return Allocation.createFromBitmap(mRS, b,
+                                           Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                           Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    private void loadImages() {
+        mTexTorus = loadTextureRGB(R.drawable.torusmap);
+        mTexOpaque = loadTextureRGB(R.drawable.data);
+        mTexTransparent = loadTextureARGB(R.drawable.leaf);
+        mTexChecker = loadTextureRGB(R.drawable.checker);
+        Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
+        mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
+
+        mScript.set_gTexTorus(mTexTorus);
+        mScript.set_gTexOpaque(mTexOpaque);
+        mScript.set_gTexTransparent(mTexTransparent);
+        mScript.set_gTexChecker(mTexChecker);
+        mScript.set_gTexCube(mTexCube);
+    }
+
+    private void initFonts() {
+        // Sans font by family name
+        mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8);
+        mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8);
+        // Create fonts by family and style
+        mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
+        mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
+        mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
+        mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8);
+
+        mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT);
+
+        mScript.set_gFontSans(mFontSans);
+        mScript.set_gFontSerif(mFontSerif);
+        mScript.set_gFontSerifBold(mFontSerifBold);
+        mScript.set_gFontSerifItalic(mFontSerifItalic);
+        mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic);
+        mScript.set_gFontMono(mFontMono);
+        mScript.set_gTextAlloc(mTextAlloc);
+    }
+
+    private void initMesh() {
+        mMbyNMesh = getMbyNMesh(256, 256, 10, 10);
+        mScript.set_gMbyNMesh(mMbyNMesh);
+
+        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
+        FileA3D.IndexEntry entry = model.getIndexEntry(0);
+        if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) {
+            Log.e("rs", "could not load model");
+        } else {
+            mTorus = (Mesh)entry.getObject();
+            mScript.set_gTorusMesh(mTorus);
+        }
+    }
+
+    private void initSamplers() {
+        Sampler.Builder bs = new Sampler.Builder(mRS);
+        bs.setMinification(Sampler.Value.LINEAR);
+        bs.setMagnification(Sampler.Value.LINEAR);
+        bs.setWrapS(Sampler.Value.WRAP);
+        bs.setWrapT(Sampler.Value.WRAP);
+        mLinearWrap = bs.create();
+
+        mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
+        mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
+        mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
+
+        bs = new Sampler.Builder(mRS);
+        bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR);
+        bs.setMagnification(Sampler.Value.LINEAR);
+        bs.setWrapS(Sampler.Value.WRAP);
+        bs.setWrapT(Sampler.Value.WRAP);
+        bs.setAnisotropy(8.0f);
+        mMipLinearAniso8 = bs.create();
+        bs.setAnisotropy(15.0f);
+        mMipLinearAniso15 = bs.create();
+
+        mScript.set_gLinearClamp(mLinearClamp);
+        mScript.set_gLinearWrap(mLinearWrap);
+        mScript.set_gMipLinearWrap(mMipLinearWrap);
+        mScript.set_gMipLinearAniso8(mMipLinearAniso8);
+        mScript.set_gMipLinearAniso15(mMipLinearAniso15);
+        mScript.set_gNearestClamp(mNearestClamp);
+    }
+
+    private void initProgramRaster() {
+        mCullBack = ProgramRaster.CULL_BACK(mRS);
+        mCullFront = ProgramRaster.CULL_FRONT(mRS);
+        mCullNone = ProgramRaster.CULL_NONE(mRS);
+
+        mScript.set_gCullBack(mCullBack);
+        mScript.set_gCullFront(mCullFront);
+        mScript.set_gCullNone(mCullNone);
+    }
+
+    private void initRS() {
+
+        mScript = new ScriptC_rsrenderstates(mRS, mRes, R.raw.rsrenderstates);
+
+        mMaxModes = mScript.get_gMaxModes();
+
+        initSamplers();
+        initProgramStore();
+        initProgramFragment();
+        initProgramVertex();
+        initFonts();
+        loadImages();
+        initMesh();
+        initProgramRaster();
+        initCustomShaders();
+
+        mRS.bindRootScript(mScript);
+    }
+}
+
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
new file mode 100644
index 0000000..a15e38f
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.miscsamples;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+
+public class RsRenderStatesView extends RSSurfaceView {
+
+    public RsRenderStatesView(Context context) {
+        super(context);
+        ensureRenderScript();
+    }
+
+    private RenderScriptGL mRS;
+    private RsRenderStatesRS mRender;
+
+    private void ensureRenderScript() {
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            sc.setDepth(16, 24);
+            mRS = createRenderScriptGL(sc);
+            mRender = new RsRenderStatesRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ensureRenderScript();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        mRender.surfaceChanged();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mRender = null;
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+            return true;
+        }
+
+        return false;
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
new file mode 100644
index 0000000..d9d450d
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
@@ -0,0 +1,70 @@
+// Copyright (C) 2009 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+#include "rs_graphics.rsh"
+
+float gDY;
+
+rs_font gItalic;
+
+typedef struct ListAllocs_s {
+    rs_allocation text;
+} ListAllocs;
+
+ListAllocs *gList;
+
+void init() {
+    gDY = 0.0f;
+}
+
+int textPos = 0;
+
+int root(void) {
+
+    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+    textPos -= (int)gDY*2;
+    gDY *= 0.95;
+
+    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
+    rsgBindFont(gItalic);
+
+    rs_allocation listAlloc;
+    listAlloc = rsGetAllocation(gList);
+    int allocSize = rsAllocationGetDimX(listAlloc);
+
+    int width = rsgGetWidth();
+    int height = rsgGetHeight();
+
+    int itemHeight = 80;
+    int currentYPos = itemHeight + textPos;
+
+    for (int i = 0; i < allocSize; i ++) {
+        if (currentYPos - itemHeight > height) {
+            break;
+        }
+
+        if (currentYPos > 0) {
+            rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
+            rsgDrawText(gList[i].text, 30, currentYPos - 32);
+        }
+        currentYPos += itemHeight;
+    }
+
+    return 10;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
new file mode 100644
index 0000000..5dabd00
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
@@ -0,0 +1,680 @@
+// Copyright (C) 2009 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+#include "rs_graphics.rsh"
+#include "shader_def.rsh"
+
+const int gMaxModes = 11;
+
+rs_program_vertex gProgVertex;
+rs_program_fragment gProgFragmentColor;
+rs_program_fragment gProgFragmentTexture;
+
+rs_program_store gProgStoreBlendNoneDepth;
+rs_program_store gProgStoreBlendNone;
+rs_program_store gProgStoreBlendAlpha;
+rs_program_store gProgStoreBlendAdd;
+
+rs_allocation gTexOpaque;
+rs_allocation gTexTorus;
+rs_allocation gTexTransparent;
+rs_allocation gTexChecker;
+rs_allocation gTexCube;
+
+rs_mesh gMbyNMesh;
+rs_mesh gTorusMesh;
+
+rs_font gFontSans;
+rs_font gFontSerif;
+rs_font gFontSerifBold;
+rs_font gFontSerifItalic;
+rs_font gFontSerifBoldItalic;
+rs_font gFontMono;
+rs_allocation gTextAlloc;
+
+int gDisplayMode;
+
+rs_sampler gLinearClamp;
+rs_sampler gLinearWrap;
+rs_sampler gMipLinearWrap;
+rs_sampler gMipLinearAniso8;
+rs_sampler gMipLinearAniso15;
+rs_sampler gNearestClamp;
+
+rs_program_raster gCullBack;
+rs_program_raster gCullFront;
+rs_program_raster gCullNone;
+
+// Custom vertex shader compunents
+VertexShaderConstants *gVSConstants;
+VertexShaderConstants2 *gVSConstants2;
+FragentShaderConstants *gFSConstants;
+FragentShaderConstants2 *gFSConstants2;
+// Export these out to easily set the inputs to shader
+VertexShaderInputs *gVSInputs;
+// Custom shaders we use for lighting
+rs_program_vertex gProgVertexCustom;
+rs_program_fragment gProgFragmentCustom;
+rs_program_vertex gProgVertexCustom2;
+rs_program_fragment gProgFragmentCustom2;
+rs_program_vertex gProgVertexCube;
+rs_program_fragment gProgFragmentCube;
+rs_program_fragment gProgFragmentMultitex;
+
+float gDt = 0;
+
+void init() {
+}
+
+static void displayFontSamples() {
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    int yPos = 100;
+    rsgBindFont(gFontSans);
+    rsgDrawText("Sans font sample", 30, yPos);
+    yPos += 30;
+    rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
+    rsgBindFont(gFontSerif);
+    rsgDrawText("Serif font sample", 30, yPos);
+    yPos += 30;
+    rsgFontColor(0.7f, 0.7f, 0.7f, 1.0f);
+    rsgBindFont(gFontSerifBold);
+    rsgDrawText("Serif Bold font sample", 30, yPos);
+    yPos += 30;
+    rsgFontColor(0.5f, 0.5f, 0.9f, 1.0f);
+    rsgBindFont(gFontSerifItalic);
+    rsgDrawText("Serif Italic font sample", 30, yPos);
+    yPos += 30;
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontSerifBoldItalic);
+    rsgDrawText("Serif Bold Italic font sample", 30, yPos);
+    yPos += 30;
+    rsgBindFont(gFontMono);
+    rsgDrawText("Monospace font sample", 30, yPos);
+    yPos += 50;
+
+    // Now use text metrics to center the text
+    uint width = rsgGetWidth();
+    uint height = rsgGetHeight();
+    int left = 0, right = 0, top = 0, bottom = 0;
+
+    rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
+    rsgBindFont(gFontSerifBoldItalic);
+
+    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
+    int centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(gTextAlloc, centeredPos, yPos);
+    yPos += 30;
+
+    const char* text = "Centered Text Sample";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, yPos);
+    yPos += 30;
+
+    rsgBindFont(gFontSans);
+    text = "More Centered Text Samples";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, yPos);
+    yPos += 30;
+
+    // Now draw bottom and top right aligned text
+    text = "Top-right aligned text";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, width - right, top);
+
+    text = "Top-left";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, -left, top);
+
+    text = "Bottom-right aligned text";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, width - right, height + bottom);
+
+}
+
+static void bindProgramVertexOrtho() {
+    // Default vertex sahder
+    rsgBindProgramVertex(gProgVertex);
+    // Setup the projectioni matrix
+    rs_matrix4x4 proj;
+    rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+}
+
+static void displayShaderSamples() {
+    bindProgramVertexOrtho();
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNone);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+    float startX = 0, startY = 0;
+    float width = 256, height = 256;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1,
+                         startX + width, startY + height, 0, 1, 1,
+                         startX + width, startY, 0, 1, 0);
+
+    startX = 200; startY = 0;
+    width = 128; height = 128;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1,
+                         startX + width, startY + height, 0, 1, 1,
+                         startX + width, startY, 0, 1, 0);
+
+    rsgBindProgramStore(gProgStoreBlendAlpha);
+    rsgBindTexture(gProgFragmentTexture, 0, gTexTransparent);
+    startX = 0; startY = 200;
+    width = 128; height = 128;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1,
+                         startX + width, startY + height, 0, 1, 1,
+                         startX + width, startY, 0, 1, 0);
+
+    // Fragment program with simple color
+    rsgBindProgramFragment(gProgFragmentColor);
+    rsgProgramFragmentConstantColor(gProgFragmentColor, 0.9, 0.3, 0.3, 1);
+    rsgDrawRect(200, 300, 350, 450, 0);
+    rsgProgramFragmentConstantColor(gProgFragmentColor, 0.3, 0.9, 0.3, 1);
+    rsgDrawRect(50, 400, 400, 600, 0);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Texture shader", 10, 50);
+    rsgDrawText("Alpha-blended texture shader", 10, 280);
+    rsgDrawText("Flat color shader", 100, 450);
+}
+
+static void displayBlendingSamples() {
+    int i;
+
+    bindProgramVertexOrtho();
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    rsgBindProgramFragment(gProgFragmentColor);
+
+    rsgBindProgramStore(gProgStoreBlendNone);
+    for (i = 0; i < 3; i ++) {
+        float iPlusOne = (float)(i + 1);
+        rsgProgramFragmentConstantColor(gProgFragmentColor,
+                                        0.1f*iPlusOne, 0.2f*iPlusOne, 0.3f*iPlusOne, 1);
+        float yPos = 150 * (float)i;
+        rsgDrawRect(0, yPos, 200, yPos + 200, 0);
+    }
+
+    rsgBindProgramStore(gProgStoreBlendAlpha);
+    for (i = 0; i < 3; i ++) {
+        float iPlusOne = (float)(i + 1);
+        rsgProgramFragmentConstantColor(gProgFragmentColor,
+                                        0.2f*iPlusOne, 0.3f*iPlusOne, 0.1f*iPlusOne, 0.5);
+        float yPos = 150 * (float)i;
+        rsgDrawRect(150, yPos, 350, yPos + 200, 0);
+    }
+
+    rsgBindProgramStore(gProgStoreBlendAdd);
+    for (i = 0; i < 3; i ++) {
+        float iPlusOne = (float)(i + 1);
+        rsgProgramFragmentConstantColor(gProgFragmentColor,
+                                        0.3f*iPlusOne, 0.1f*iPlusOne, 0.2f*iPlusOne, 0.5);
+        float yPos = 150 * (float)i;
+        rsgDrawRect(300, yPos, 500, yPos + 200, 0);
+    }
+
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("No Blending", 10, 50);
+    rsgDrawText("Alpha Blending", 160, 150);
+    rsgDrawText("Additive Blending", 320, 250);
+
+}
+
+static void displayMeshSamples() {
+
+    bindProgramVertexOrtho();
+    rs_matrix4x4 matrix;
+    rsMatrixLoadTranslate(&matrix, 128, 128, 0);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNone);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+    rsgDrawMesh(gMbyNMesh);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("User gen 10 by 10 grid mesh", 10, 250);
+}
+
+static void displayTextureSamplers() {
+
+    bindProgramVertexOrtho();
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNone);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+
+    // Linear clamp
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+    float startX = 0, startY = 0;
+    float width = 300, height = 300;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1.1,
+                         startX + width, startY + height, 0, 1.1, 1.1,
+                         startX + width, startY, 0, 1.1, 0);
+
+    // Linear Wrap
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearWrap);
+    startX = 0; startY = 300;
+    width = 300; height = 300;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1.1,
+                         startX + width, startY + height, 0, 1.1, 1.1,
+                         startX + width, startY, 0, 1.1, 0);
+
+    // Nearest
+    rsgBindSampler(gProgFragmentTexture, 0, gNearestClamp);
+    startX = 300; startY = 0;
+    width = 300; height = 300;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1.1,
+                         startX + width, startY + height, 0, 1.1, 1.1,
+                         startX + width, startY, 0, 1.1, 0);
+
+    rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
+    startX = 300; startY = 300;
+    width = 300; height = 300;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1.5,
+                         startX + width, startY + height, 0, 1.5, 1.5,
+                         startX + width, startY, 0, 1.5, 0);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Filtering: linear clamp", 10, 290);
+    rsgDrawText("Filtering: linear wrap", 10, 590);
+    rsgDrawText("Filtering: nearest clamp", 310, 290);
+    rsgDrawText("Filtering: miplinear wrap", 310, 590);
+}
+
+static float gTorusRotation = 0;
+
+static void displayCullingSamples() {
+    rsgBindProgramVertex(gProgVertex);
+    // Setup the projectioni matrix with 60 degree field of view
+    rs_matrix4x4 proj;
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNoneDepth);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
+
+    // Aplly a rotation to our mesh
+    gTorusRotation += 50.0f * gDt;
+    if (gTorusRotation > 360.0f) {
+        gTorusRotation -= 360.0f;
+    }
+
+    rs_matrix4x4 matrix;
+    // Position our model on the screen
+    rsMatrixLoadTranslate(&matrix, -2.0f, 0.0f, -10.0f);
+    rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+    // Use front face culling
+    rsgBindProgramRaster(gCullFront);
+    rsgDrawMesh(gTorusMesh);
+
+    rsMatrixLoadTranslate(&matrix, 2.0f, 0.0f, -10.0f);
+    rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+    // Use back face culling
+    rsgBindProgramRaster(gCullBack);
+    rsgDrawMesh(gTorusMesh);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Displaying mesh front/back face culling", 10, rsgGetHeight() - 10);
+}
+
+static float gLight0Rotation = 0;
+static float gLight1Rotation = 0;
+
+static void setupCustomShaderLights() {
+    float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
+    float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
+    float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
+    float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
+    float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
+    float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
+
+    gLight0Rotation += 50.0f * gDt;
+    if (gLight0Rotation > 360.0f) {
+        gLight0Rotation -= 360.0f;
+    }
+    gLight1Rotation -= 50.0f * gDt;
+    if (gLight1Rotation > 360.0f) {
+        gLight1Rotation -= 360.0f;
+    }
+
+    rs_matrix4x4 l0Mat;
+    rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
+    light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
+    rs_matrix4x4 l1Mat;
+    rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
+    light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
+
+    // Set light 0 properties
+    gVSConstants->light0_Posision = light0Pos;
+    gVSConstants->light0_Diffuse = 1.0f;
+    gVSConstants->light0_Specular = 0.5f;
+    gVSConstants->light0_CosinePower = 10.0f;
+    // Set light 1 properties
+    gVSConstants->light1_Posision = light1Pos;
+    gVSConstants->light1_Diffuse = 1.0f;
+    gVSConstants->light1_Specular = 0.7f;
+    gVSConstants->light1_CosinePower = 25.0f;
+    rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
+
+    gVSConstants2->light_Posision[0] = light0Pos;
+    gVSConstants2->light_Diffuse[0] = 1.0f;
+    gVSConstants2->light_Specular[0] = 0.5f;
+    gVSConstants2->light_CosinePower[0] = 10.0f;
+    gVSConstants2->light_Posision[1] = light1Pos;
+    gVSConstants2->light_Diffuse[1] = 1.0f;
+    gVSConstants2->light_Specular[1] = 0.7f;
+    gVSConstants2->light_CosinePower[1] = 25.0f;
+    rsgAllocationSyncAll(rsGetAllocation(gVSConstants2));
+
+    // Update fragmetn shader constants
+    // Set light 0 colors
+    gFSConstants->light0_DiffuseColor = light0DiffCol;
+    gFSConstants->light0_SpecularColor = light0SpecCol;
+    // Set light 1 colors
+    gFSConstants->light1_DiffuseColor = light1DiffCol;
+    gFSConstants->light1_SpecularColor = light1SpecCol;
+    rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+    gFSConstants2->light_DiffuseColor[0] = light0DiffCol;
+    gFSConstants2->light_SpecularColor[0] = light0SpecCol;
+    // Set light 1 colors
+    gFSConstants2->light_DiffuseColor[1] = light1DiffCol;
+    gFSConstants2->light_SpecularColor[1] = light1SpecCol;
+    rsgAllocationSyncAll(rsGetAllocation(gFSConstants2));
+}
+
+static void displayCustomShaderSamples() {
+
+    // Update vertex shader constants
+    // Load model matrix
+    // Aplly a rotation to our mesh
+    gTorusRotation += 50.0f * gDt;
+    if (gTorusRotation > 360.0f) {
+        gTorusRotation -= 360.0f;
+    }
+
+    // Position our model on the screen
+    rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
+    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
+    // Setup the projectioni matrix
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+    setupCustomShaderLights();
+
+    rsgBindProgramVertex(gProgVertexCustom);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNoneDepth);
+    rsgBindProgramFragment(gProgFragmentCustom);
+    rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
+
+    // Use back face culling
+    rsgBindProgramRaster(gCullBack);
+    rsgDrawMesh(gTorusMesh);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Custom shader sample", 10, rsgGetHeight() - 10);
+}
+
+static void displayCustomShaderSamples2() {
+
+    // Update vertex shader constants
+    // Load model matrix
+    // Aplly a rotation to our mesh
+    gTorusRotation += 50.0f * gDt;
+    if (gTorusRotation > 360.0f) {
+        gTorusRotation -= 360.0f;
+    }
+
+    // Position our model on the screen
+    rsMatrixLoadTranslate(&gVSConstants2->model[1], 0.0f, 0.0f, -10.0f);
+    rsMatrixLoadIdentity(&gVSConstants2->model[0]);
+    rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 0.0f, 0.0f, 1.0f);
+    // Setup the projectioni matrix
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&gVSConstants2->proj, 30.0f, aspect, 0.1f, 100.0f);
+    setupCustomShaderLights();
+
+    rsgBindProgramVertex(gProgVertexCustom2);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNoneDepth);
+    rsgBindProgramFragment(gProgFragmentCustom2);
+    rsgBindSampler(gProgFragmentCustom2, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentCustom2, 0, gTexTorus);
+
+    // Use back face culling
+    rsgBindProgramRaster(gCullBack);
+    rsgDrawMesh(gTorusMesh);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Custom shader sample with array uniforms", 10, rsgGetHeight() - 10);
+}
+
+static void displayCubemapShaderSample() {
+    // Update vertex shader constants
+    // Load model matrix
+    // Aplly a rotation to our mesh
+    gTorusRotation += 50.0f * gDt;
+    if (gTorusRotation > 360.0f) {
+        gTorusRotation -= 360.0f;
+    }
+
+    // Position our model on the screen
+    // Position our model on the screen
+    rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
+    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
+    // Setup the projectioni matrix
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+    rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+    rsgBindProgramVertex(gProgVertexCube);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNoneDepth);
+    rsgBindProgramFragment(gProgFragmentCube);
+    rsgBindSampler(gProgFragmentCube, 0, gLinearClamp);
+    rsgBindTexture(gProgFragmentCube, 0, gTexCube);
+
+    // Use back face culling
+    rsgBindProgramRaster(gCullBack);
+    rsgDrawMesh(gTorusMesh);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Cubemap shader sample", 10, rsgGetHeight() - 10);
+}
+
+static void displayMultitextureSample() {
+    bindProgramVertexOrtho();
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNone);
+    rsgBindProgramFragment(gProgFragmentMultitex);
+    rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp);
+    rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap);
+    rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp);
+    rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker);
+    rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus);
+    rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent);
+
+    float startX = 0, startY = 0;
+    float width = 256, height = 256;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 1,
+                         startX + width, startY + height, 0, 1, 1,
+                         startX + width, startY, 0, 1, 0);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    rsgDrawText("Custom shader with multitexturing", 10, 280);
+}
+
+static float gAnisoTime = 0.0f;
+static uint anisoMode = 0;
+static void displayAnisoSample() {
+
+    gAnisoTime += gDt;
+
+    rsgBindProgramVertex(gProgVertex);
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rs_matrix4x4 proj;
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+
+    rs_matrix4x4 matrix;
+    // Fragment shader with texture
+    rsgBindProgramStore(gProgStoreBlendNone);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -10.0f);
+    rsMatrixRotate(&matrix, -80, 1.0f, 0.0f, 0.0f);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    rsgBindProgramRaster(gCullNone);
+
+    rsgBindTexture(gProgFragmentTexture, 0, gTexChecker);
+
+    if (gAnisoTime >= 5.0f) {
+        gAnisoTime = 0.0f;
+        anisoMode ++;
+        anisoMode = anisoMode % 3;
+    }
+
+    if (anisoMode == 0) {
+        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso8);
+    } else if (anisoMode == 1) {
+        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso15);
+    } else {
+        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
+    }
+
+    float startX = -15;
+    float startY = -15;
+    float width = 30;
+    float height = 30;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
+                         startX, startY + height, 0, 0, 10,
+                         startX + width, startY + height, 0, 10, 10,
+                         startX + width, startY, 0, 10, 0);
+
+    rsgBindProgramRaster(gCullBack);
+
+    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgBindFont(gFontMono);
+    if (anisoMode == 0) {
+        rsgDrawText("Anisotropic filtering 8", 10, 40);
+    } else if (anisoMode == 1) {
+        rsgDrawText("Anisotropic filtering 15", 10, 40);
+    } else {
+        rsgDrawText("Miplinear filtering", 10, 40);
+    }
+}
+
+int root(void) {
+
+    gDt = rsGetDt();
+
+    rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
+    rsgClearDepth(1.0f);
+
+    switch (gDisplayMode) {
+    case 0:
+        displayFontSamples();
+        break;
+    case 1:
+        displayShaderSamples();
+        break;
+    case 2:
+        displayBlendingSamples();
+        break;
+    case 3:
+        displayMeshSamples();
+        break;
+    case 4:
+        displayTextureSamplers();
+        break;
+    case 5:
+        displayCullingSamples();
+        break;
+    case 6:
+        displayCustomShaderSamples();
+        break;
+    case 7:
+        displayMultitextureSample();
+        break;
+    case 8:
+        displayAnisoSample();
+        break;
+    case 9:
+        displayCustomShaderSamples2();
+        break;
+    case 10:
+        displayCubemapShaderSample();
+        break;
+    }
+
+    return 10;
+}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
new file mode 100644
index 0000000..08cf361
--- /dev/null
+++ b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
@@ -0,0 +1,83 @@
+// Copyright (C) 2009 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.example.android.rs.miscsamples)
+
+typedef struct VertexShaderConstants_s {
+    rs_matrix4x4 model;
+    rs_matrix4x4 proj;
+    float4 light0_Posision;
+    float light0_Diffuse;
+    float light0_Specular;
+    float light0_CosinePower;
+
+    float4 light1_Posision;
+    float light1_Diffuse;
+    float light1_Specular;
+    float light1_CosinePower;
+} VertexShaderConstants;
+
+typedef struct VertexShaderConstants2_s {
+    rs_matrix4x4 model[2];
+    rs_matrix4x4 proj;
+    float4 light_Posision[2];
+    float light_Diffuse[2];
+    float light_Specular[2];
+    float light_CosinePower[2];
+} VertexShaderConstants2;
+
+typedef struct VertexShaderConstants3_s {
+    rs_matrix4x4 model;
+    rs_matrix4x4 proj;
+    float time;
+} VertexShaderConstants3;
+
+
+typedef struct FragentShaderConstants_s {
+    float4 light0_DiffuseColor;
+    float4 light0_SpecularColor;
+
+    float4 light1_DiffuseColor;
+    float4 light1_SpecularColor;
+} FragentShaderConstants;
+
+typedef struct FragentShaderConstants2_s {
+    float4 light_DiffuseColor[2];
+    float4 light_SpecularColor[2];
+} FragentShaderConstants2;
+
+typedef struct FragentShaderConstants3_s {
+    float4 light0_DiffuseColor;
+    float4 light0_SpecularColor;
+    float4 light0_Posision;
+    float light0_Diffuse;
+    float light0_Specular;
+    float light0_CosinePower;
+
+    float4 light1_DiffuseColor;
+    float4 light1_SpecularColor;
+    float4 light1_Posision;
+    float light1_Diffuse;
+    float light1_Specular;
+    float light1_CosinePower;
+} FragentShaderConstants3;
+
+typedef struct VertexShaderInputs_s {
+    float4 position;
+    float3 normal;
+    float2 texture0;
+} VertexShaderInputs;
+
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index ec61403..f2fa3f5 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -56,55 +56,93 @@
     return true;
 }
 
+// The default to use if no other ignore pattern is defined.
+const char * const gDefaultIgnoreAssets =
+    "!.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~";
+// The ignore pattern that can be passed via --ignore-assets in Main.cpp
+const char * gUserIgnoreAssets = NULL;
+
 static bool isHidden(const char *root, const char *path)
 {
-    const char *ext  = NULL;
-    const char *type = NULL;
+    // Patterns syntax:
+    // - Delimiter is :
+    // - Entry can start with the flag ! to avoid printing a warning
+    //   about the file being ignored.
+    // - Entry can have the flag "<dir>" to match only directories
+    //   or <file> to match only files. Default is to match both.
+    // - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
+    //   where prefix/suffix must have at least 1 character (so that
+    //   we don't match a '*' catch-all pattern.)
+    // - The special filenames "." and ".." are always ignored.
+    // - Otherwise the full string is matched.
+    // - match is not case-sensitive.
 
-    // Skip all hidden files.
-    if (path[0] == '.') {
-        // Skip ., .. and  .svn but don't chatter about it.
-        if (strcmp(path, ".") == 0
-            || strcmp(path, "..") == 0
-            || strcmp(path, ".svn") == 0) {
-            return true;
-        }
-        type = "hidden";
-    } else if (path[0] == '_') {
-        // skip directories starting with _ (don't chatter about it)
-        String8 subdirName(root);
-        subdirName.appendPath(path);
-        if (getFileType(subdirName.string()) == kFileTypeDirectory) {
-            return true;
-        }
-    } else if (strcmp(path, "CVS") == 0) {
-        // Skip CVS but don't chatter about it.
+    if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
         return true;
-    } else if (strcasecmp(path, "thumbs.db") == 0
-               || strcasecmp(path, "picasa.ini") == 0) {
-        // Skip suspected image indexes files.
-        type = "index";
-    } else if (path[strlen(path)-1] == '~') {
-        // Skip suspected emacs backup files.
-        type = "backup";
-    } else if ((ext = strrchr(path, '.')) != NULL && strcmp(ext, ".scc") == 0) {
-        // Skip VisualSourceSafe files and don't chatter about it
-        return true;
-    } else {
-        // Let everything else through.
-        return false;
     }
 
-    /* If we get this far, "type" should be set and the file
-     * should be skipped.
-     */
-    String8 subdirName(root);
-    subdirName.appendPath(path);
-    fprintf(stderr, "    (skipping %s %s '%s')\n", type,
-            getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file",
-            subdirName.string());
+    const char *delim = ":";
+    const char *p = gUserIgnoreAssets;
+    if (!p || !p[0]) {
+        p = getenv("ANDROID_AAPT_IGNORE");
+    }
+    if (!p || !p[0]) {
+        p = gDefaultIgnoreAssets;
+    }
+    char *patterns = strdup(p);
 
-    return true;
+    bool ignore = false;
+    bool chatty = true;
+    char *matchedPattern = NULL;
+
+    String8 fullPath(root);
+    fullPath.appendPath(path);
+    FileType type = getFileType(fullPath);
+
+    int plen = strlen(path);
+
+    // Note: we don't have strtok_r under mingw.
+    for(char *token = strtok(patterns, delim);
+            !ignore && token != NULL;
+            token = strtok(NULL, delim)) {
+        chatty = token[0] != '!';
+        if (!chatty) token++; // skip !
+        if (strncasecmp(token, "<dir>" , 5) == 0) {
+            if (type != kFileTypeDirectory) continue;
+            token += 5;
+        }
+        if (strncasecmp(token, "<file>", 6) == 0) {
+            if (type != kFileTypeRegular) continue;
+            token += 6;
+        }
+
+        matchedPattern = token;
+        int n = strlen(token);
+
+        if (token[0] == '*') {
+            // Match *suffix
+            token++;
+            n--;
+            if (n <= plen) {
+                ignore = strncasecmp(token, path + plen - n, n) == 0;
+            }
+        } else if (n > 1 && token[n - 1] == '*') {
+            // Match prefix*
+            ignore = strncasecmp(token, path, n - 1) == 0;
+        } else {
+            ignore = strcasecmp(token, path) == 0;
+        }
+    }
+
+    if (ignore && chatty) {
+        fprintf(stderr, "    (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
+                type == kFileTypeDirectory ? "dir" : "file",
+                path,
+                matchedPattern ? matchedPattern : "");
+    }
+
+    free(patterns);
+    return ignore;
 }
 
 // =========================================================================
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 5924952..d5f296c 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -22,6 +22,10 @@
 
 using namespace android;
 
+
+extern const char * const gDefaultIgnoreAssets;
+extern const char * gUserIgnoreAssets;
+
 bool valid_symbol_name(const String8& str);
 
 class AaptAssets;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 50c828d..9f05c6a 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -178,7 +178,11 @@
         "   --non-constant-id\n"
         "       Make the resources ID non constant. This is required to make an R java class\n"
         "       that does not contain the final value but is used to make reusable compiled\n"
-        "       libraries that need to access resources.\n");
+        "       libraries that need to access resources.\n"
+        "   --ignore-assets\n"
+        "       Assets to be ignored. Default pattern is:\n"
+        "       %s\n",
+        gDefaultIgnoreAssets);
 }
 
 /*
@@ -556,7 +560,16 @@
                     bundle.setNonConstantId(true);
                 } else if (strcmp(cp, "-no-crunch") == 0) {
                     bundle.setUseCrunchCache(true);
-                }else {
+                } else if (strcmp(cp, "-ignore-assets") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--ignore-assets' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    gUserIgnoreAssets = argv[0];
+                } else {
                     fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
                     wantUsage = true;
                     goto bail;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index b9ec30c..a69adc1 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2089,6 +2089,23 @@
     keep->add(rule, location);
 }
 
+void
+addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName,
+        const char* pkg, const String8& srcName, int line)
+{
+    String8 rule("-keepclassmembers class * { *** ");
+    rule += memberName;
+    rule += "(...); }";
+
+    String8 location("onClick ");
+    location += srcName;
+    char lineno[20];
+    sprintf(lineno, ":%d", line);
+    location += lineno;
+
+    keep->add(rule, location);
+}
+
 status_t
 writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
 {
@@ -2251,6 +2268,13 @@
                 }
             }
         }
+        ssize_t attrIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "onClick");
+        if (attrIndex >= 0) {
+            size_t len;
+            addProguardKeepMethodRule(keep,
+                                String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
+                                layoutFile->getPrintableSource(), tree.getLineNumber());
+        }
     }
 
     return NO_ERROR;
@@ -2289,6 +2313,9 @@
         } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
             startTag = "PreferenceScreen";
             tagAttrPairs = &kXmlTagAttrPairs;
+        } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
+            startTag = "menu";
+            tagAttrPairs = NULL;
         } else {
             continue;
         }
diff --git a/tools/preload/Record.java b/tools/preload/Record.java
index 2f2ffaf..ac99f1c 100644
--- a/tools/preload/Record.java
+++ b/tools/preload/Record.java
@@ -30,8 +30,22 @@
             "com.google.android.apps.maps\\u003Adriveabout",
             "com.google.android.apps.maps:LocationFriendService",
             "com.google.android.apps.maps\\u003ALocationFriendService",
+            "com.google.android.apps.maps:MapsBackgroundService",
+            "com.google.android.apps.maps\\u003AMapsBackgroundService",
             "com.google.android.apps.maps:NetworkLocationService",
             "com.google.android.apps.maps\\u003ANetworkLocationService",
+            "com.android.fakeoemfeatures:background",
+            "com.android.fakeoemfeatures\\u003Abackground",
+            "com.android.fakeoemfeatures:core",
+            "com.android.fakeoemfeatures\\u003Acore",
+            "com.google.android.music:main",
+            "com.google.android.music\\u003Amain",
+            "com.google.android.music:ui",
+            "com.google.android.music\\u003Aui",
+            "com.google.android.setupwarlock:broker",
+            "com.google.android.setupwarlock\\u003Abroker",
+            "android:ui",
+            "android\\u003Aui",
     };
 
     enum Type {
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 0a87a538..63359c1 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -438,6 +438,22 @@
         return doBooleanCommand("SET config_methods " + cfg);
     }
 
+    public boolean setManufacturer(String value) {
+        return doBooleanCommand("SET manufacturer " + value);
+    }
+
+    public boolean setModelName(String value) {
+        return doBooleanCommand("SET model_name " + value);
+    }
+
+    public boolean setModelNumber(String value) {
+        return doBooleanCommand("SET model_number " + value);
+    }
+
+    public boolean setSerialNumber(String value) {
+        return doBooleanCommand("SET serial_number " + value);
+    }
+
     public boolean setP2pSsidPostfix(String postfix) {
         return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 2903faa..7f8f9ce 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -120,6 +120,7 @@
     private ConnectivityManager mCm;
 
     private final boolean mP2pSupported;
+    private final String mPrimaryDeviceType;
 
     /* Scan results handling */
     private List<ScanResult> mScanResults;
@@ -208,6 +209,8 @@
 
     private AlarmManager mAlarmManager;
     private PendingIntent mScanIntent;
+    private PendingIntent mDriverStopIntent;
+
     /* Tracks current frequency mode */
     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
 
@@ -520,6 +523,11 @@
     private static final String ACTION_START_SCAN =
         "com.android.server.WifiManager.action.START_SCAN";
 
+    private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
+    private static final int DRIVER_STOP_REQUEST = 0;
+    private static final String ACTION_DELAYED_DRIVER_STOP =
+        "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
+
     /**
      * Keep track of whether WIFI is running.
      */
@@ -590,6 +598,9 @@
         mBackgroundScanSupported = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_wifi_background_scan_support);
 
+        mPrimaryDeviceType = mContext.getResources().getString(
+                com.android.internal.R.string.config_wifi_p2p_device_type);
+
         mContext.registerReceiver(
             new BroadcastReceiver() {
                 @Override
@@ -637,6 +648,15 @@
                 }
             }
         };
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                       int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
+                       sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, counter, 0));
+                    }
+                },
+                new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
 
         mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
 
@@ -2214,6 +2234,37 @@
             if (DBG) log(getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
         }
+
+        private void initializeWpsDetails() {
+            String detail;
+            detail = SystemProperties.get("ro.product.name", "");
+            if (!mWifiNative.setDeviceName(detail)) {
+                loge("Failed to set device name " +  detail);
+            }
+            detail = SystemProperties.get("ro.product.manufacturer", "");
+            if (!mWifiNative.setManufacturer(detail)) {
+                loge("Failed to set manufacturer " + detail);
+            }
+            detail = SystemProperties.get("ro.product.model", "");
+            if (!mWifiNative.setModelName(detail)) {
+                loge("Failed to set model name " + detail);
+            }
+            detail = SystemProperties.get("ro.product.model", "");
+            if (!mWifiNative.setModelNumber(detail)) {
+                loge("Failed to set model number " + detail);
+            }
+            detail = SystemProperties.get("ro.serialno", "");
+            if (!mWifiNative.setSerialNumber(detail)) {
+                loge("Failed to set serial number " + detail);
+            }
+            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) {
+                loge("Failed to set WPS config methods");
+            }
+            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
+                loge("Failed to set primary device type " + mPrimaryDeviceType);
+            }
+        }
+
         @Override
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
@@ -2231,8 +2282,8 @@
                     mLastSignalLevel = -1;
 
                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
-
                     mWifiConfigStore.initialize();
+                    initializeWpsDetails();
 
                     sendSupplicantConnectionChangedBroadcast(true);
                     transitionTo(mDriverStartedState);
@@ -2666,18 +2717,26 @@
                         sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
                     } else {
                         /* send regular delayed shut down */
-                        sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER,
-                                mDelayedStopCounter, 0), mDriverStopDelayMs);
+                        Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
+                        driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
+                        mDriverStopIntent = PendingIntent.getBroadcast(mContext,
+                                DRIVER_STOP_REQUEST, driverStopIntent,
+                                PendingIntent.FLAG_UPDATE_CURRENT);
+
+                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+                                + mDriverStopDelayMs, mDriverStopIntent);
                     }
                     break;
                 case CMD_START_DRIVER:
                     if (mInDelayedStop) {
                         mInDelayedStop = false;
                         mDelayedStopCounter++;
+                        mAlarmManager.cancel(mDriverStopIntent);
                         if (DBG) log("Delayed stop ignored due to start");
                     }
                     break;
                 case CMD_DELAYED_STOP_DRIVER:
+                    if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
                     if (message.arg1 != mDelayedStopCounter) break;
                     if (getCurrentState() != mDisconnectedState) {
                         mWifiNative.disconnect();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index cc49cae..c800182 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -425,6 +425,12 @@
                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
+                case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
+                case WifiMonitor.P2P_DEVICE_LOST_EVENT:
+                case WifiMonitor.P2P_FIND_STOPPED_EVENT:
+                case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
+                case WifiStateMachine.CMD_ENABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P:
                 case PEER_CONNECTION_USER_ACCEPT:
                 case PEER_CONNECTION_USER_REJECT:
                 case GROUP_CREATING_TIMED_OUT:
@@ -837,6 +843,13 @@
                         transitionTo(mUserAuthorizingInvitationState);
                     }
                     break;
+                case WifiMonitor.P2P_FIND_STOPPED_EVENT:
+                    // When discovery stops in inactive state, flush to clear
+                    // state peer data
+                    mWifiNative.p2pFlush();
+                    mServiceDiscReqId = null;
+                    sendP2pDiscoveryChangedBroadcast(false);
+                    break;
                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
@@ -873,6 +886,7 @@
         @Override
         public boolean processMessage(Message message) {
             if (DBG) logd(getName() + message.toString());
+            boolean ret = HANDLED;
             switch (message.what) {
                case GROUP_CREATING_TIMED_OUT:
                     if (mGroupCreatingTimeoutIndex == message.arg1) {
@@ -881,6 +895,16 @@
                         transitionTo(mInactiveState);
                     }
                     break;
+                case WifiMonitor.P2P_DEVICE_LOST_EVENT:
+                    WifiP2pDevice device = (WifiP2pDevice) message.obj;
+                    if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
+                        // Do the regular device lost handling
+                        ret = NOT_HANDLED;
+                        break;
+                    }
+                    // Do nothing
+                    if (DBG) logd("Retain connecting device " + device);
+                    break;
                 case WifiP2pManager.DISCOVER_PEERS:
                     /* Discovery will break negotiation */
                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
@@ -898,9 +922,9 @@
                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
                     break;
                 default:
-                    return NOT_HANDLED;
+                    ret = NOT_HANDLED;
             }
-            return HANDLED;
+            return ret;
         }
     }