Merge "Full-height panels on phones." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index fbda3c6..4a99427 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -947,6 +947,7 @@
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int subtypeExtraValue = 16843674; // 0x101039a
+    field public static final int subtypeId = 16843713; // 0x10103c1
     field public static final int subtypeLocale = 16843673; // 0x1010399
     field public static final int suggestActionMsg = 16843228; // 0x10101dc
     field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
@@ -4179,6 +4180,7 @@
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int USES_ENCRYPTED_STORAGE = 7; // 0x7
     field public static final int USES_POLICY_DISABLE_CAMERA = 8; // 0x8
+    field public static final int USES_POLICY_DISABLE_KEYGUARD_WIDGETS = 9; // 0x9
     field public static final int USES_POLICY_EXPIRE_PASSWORD = 6; // 0x6
     field public static final int USES_POLICY_FORCE_LOCK = 3; // 0x3
     field public static final int USES_POLICY_LIMIT_PASSWORD = 0; // 0x0
@@ -4214,6 +4216,7 @@
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
+    method public int getKeyguardWidgetsDisabled(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -4237,6 +4240,7 @@
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
+    method public void setKeyguardWidgetsDisabled(android.content.ComponentName, int);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
@@ -4260,6 +4264,8 @@
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
     field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
+    field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 2147483647; // 0x7fffffff
+    field public static final int KEYGUARD_DISABLE_WIDGETS_NONE = 0; // 0x0
     field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
     field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
     field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
@@ -6250,6 +6256,7 @@
     field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
     field public static final int CONFIG_KEYBOARD = 16; // 0x10
     field public static final int CONFIG_KEYBOARD_HIDDEN = 32; // 0x20
+    field public static final int CONFIG_LAYOUT_DIRECTION = 8192; // 0x2000
     field public static final int CONFIG_LOCALE = 4; // 0x4
     field public static final int CONFIG_MCC = 1; // 0x1
     field public static final int CONFIG_MNC = 2; // 0x2
@@ -6852,9 +6859,12 @@
     method public int describeContents();
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
+    method public int getLayoutDirection();
     method public boolean isLayoutSizeAtLeast(int);
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
+    method public void setLayoutDirection(java.util.Locale);
+    method public void setLocale(java.util.Locale);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
@@ -6883,6 +6893,11 @@
     field public static final int ORIENTATION_PORTRAIT = 1; // 0x1
     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_LAYOUTDIR_LTR = 64; // 0x40
+    field public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 192; // 0xc0
+    field public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 128; // 0x80
+    field public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6; // 0x6
+    field public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LONG_MASK = 48; // 0x30
     field public static final int SCREENLAYOUT_LONG_NO = 16; // 0x10
     field public static final int SCREENLAYOUT_LONG_UNDEFINED = 0; // 0x0
@@ -6893,6 +6908,7 @@
     field public static final int SCREENLAYOUT_SIZE_SMALL = 1; // 0x1
     field public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_SIZE_XLARGE = 4; // 0x4
+    field public static final int SCREENLAYOUT_UNDEFINED = 0; // 0x0
     field public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0; // 0x0
     field public static final int SCREEN_WIDTH_DP_UNDEFINED = 0; // 0x0
     field public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; // 0x0
@@ -26642,6 +26658,7 @@
 
   public final class InputMethodSubtype implements android.os.Parcelable {
     ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
+    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int);
     method public boolean containsExtraValueKey(java.lang.String);
     method public int describeContents();
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 7f3dbe5..bcd4588 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1181,12 +1181,12 @@
     private class IntentReceiver extends IIntentReceiver.Stub {
         private boolean mFinished = false;
 
-        public synchronized void performReceive(
-                Intent intent, int rc, String data, Bundle ext, boolean ord,
-                boolean sticky) {
-            String line = "Broadcast completed: result=" + rc;
+        @Override
+        public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+                boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
+            String line = "Broadcast completed: result=" + resultCode;
             if (data != null) line = line + ", data=\"" + data + "\"";
-            if (ext != null) line = line + ", extras: " + ext;
+            if (extras != null) line = line + ", extras: " + extras;
             System.out.println(line);
             mFinished = true;
             notifyAll();
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index ab64747..9e83a67 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -14,6 +14,7 @@
 ** limitations under the License.
 */
 
+#include <linux/capability.h>
 #include "installd.h"
 #include <diskusage/dirsize.h>
 
@@ -665,16 +666,16 @@
         ALOGE("dexopt cannot open '%s' for output\n", dex_path);
         goto fail;
     }
-    if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
-        ALOGE("dexopt cannot chown '%s'\n", dex_path);
-        goto fail;
-    }
     if (fchmod(odex_fd,
                S_IRUSR|S_IWUSR|S_IRGRP |
                (is_public ? S_IROTH : 0)) < 0) {
         ALOGE("dexopt cannot chmod '%s'\n", dex_path);
         goto fail;
     }
+    if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
+        ALOGE("dexopt cannot chown '%s'\n", dex_path);
+        goto fail;
+    }
 
     ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
 
@@ -690,13 +691,23 @@
             ALOGE("setuid(%d) during dexopt\n", uid);
             exit(65);
         }
+        // drop capabilities
+        struct __user_cap_header_struct capheader;
+        struct __user_cap_data_struct capdata[2];
+        memset(&capheader, 0, sizeof(capheader));
+        memset(&capdata, 0, sizeof(capdata));
+        capheader.version = _LINUX_CAPABILITY_VERSION_3;
+        if (capset(&capheader, &capdata[0]) < 0) {
+            ALOGE("capset failed: %s\n", strerror(errno));
+            exit(66);
+        }
         if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
             ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
-            exit(66);
+            exit(67);
         }
 
         run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
-        exit(67);   /* only get here on exec failure */
+        exit(68);   /* only get here on exec failure */
     } else {
         res = wait_dexopt(pid, apk_path);
         if (res != 0) {
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index d559639..652543fd 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -14,6 +14,9 @@
 ** limitations under the License.
 */
 
+#include <linux/capability.h>
+#include <linux/prctl.h>
+
 #include "installd.h"
 
 
@@ -491,12 +494,53 @@
     return res;
 }
 
+static void drop_privileges() {
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    if (setgid(AID_INSTALL) < 0) {
+        ALOGE("setgid() can't drop privileges; exiting.\n");
+        exit(1);
+    }
+
+    if (setuid(AID_INSTALL) < 0) {
+        ALOGE("setuid() can't drop privileges; exiting.\n");
+        exit(1);
+    }
+
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
+    capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted        |= CAP_TO_MASK(CAP_CHOWN);
+    capdata[CAP_TO_INDEX(CAP_SETUID)].permitted       |= CAP_TO_MASK(CAP_SETUID);
+    capdata[CAP_TO_INDEX(CAP_SETGID)].permitted       |= CAP_TO_MASK(CAP_SETGID);
+
+    capdata[0].effective = capdata[0].permitted;
+    capdata[1].effective = capdata[1].permitted;
+    capdata[0].inheritable = 0;
+    capdata[1].inheritable = 0;
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        ALOGE("capset failed: %s\n", strerror(errno));
+        exit(1);
+    }
+}
+
 int main(const int argc, const char *argv[]) {
     char buf[BUFFER_MAX];
     struct sockaddr addr;
     socklen_t alen;
     int lsocket, s, count;
 
+    ALOGI("installd firing up\n");
+
     if (initialize_globals() < 0) {
         ALOGE("Could not initialize globals; exiting.\n");
         exit(1);
@@ -507,6 +551,8 @@
         exit(1);
     }
 
+    drop_privileges();
+
     lsocket = android_get_control_socket(SOCKET_PATH);
     if (lsocket < 0) {
         ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 14ba537..eed9254 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -300,7 +300,8 @@
                 = b != null ? IIntentReceiver.Stub.asInterface(b) : null;
             IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
             String perm = data.readString();
-            Intent intent = registerReceiver(app, packageName, rec, filter, perm);
+            int userId = data.readInt();
+            Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId);
             reply.writeNoException();
             if (intent != null) {
                 reply.writeInt(1);
@@ -1999,7 +2000,7 @@
     }
     public Intent registerReceiver(IApplicationThread caller, String packageName,
             IIntentReceiver receiver,
-            IntentFilter filter, String perm) throws RemoteException
+            IntentFilter filter, String perm, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2009,6 +2010,7 @@
         data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
         filter.writeToParcel(data, 0);
         data.writeString(perm);
+        data.writeInt(userId);
         mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
         reply.readException();
         Intent intent = null;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1b788c2..97dcec0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -320,8 +320,9 @@
 
     static final class ReceiverData extends BroadcastReceiver.PendingResult {
         public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
-                boolean ordered, boolean sticky, IBinder token) {
-            super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, token);
+                boolean ordered, boolean sticky, IBinder token, int sendingUser) {
+            super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky,
+                    token, sendingUser);
             this.intent = intent;
         }
 
@@ -613,9 +614,9 @@
 
         public final void scheduleReceiver(Intent intent, ActivityInfo info,
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
-                boolean sync) {
+                boolean sync, int sendingUser) {
             ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
-                    sync, false, mAppThread.asBinder());
+                    sync, false, mAppThread.asBinder(), sendingUser);
             r.info = info;
             r.compatInfo = compatInfo;
             queueOrSendMessage(H.RECEIVER, r);
@@ -774,8 +775,9 @@
         // applies transaction ordering per object for such calls.
         public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                 int resultCode, String dataStr, Bundle extras, boolean ordered,
-                boolean sticky) throws RemoteException {
-            receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);
+                boolean sticky, int sendingUser) throws RemoteException {
+            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
+                    sticky, sendingUser);
         }
 
         public void scheduleLowMemory() {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 8e6278d..63aa5f9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -193,8 +193,9 @@
             String resultData = data.readString();
             Bundle resultExtras = data.readBundle();
             boolean sync = data.readInt() != 0;
+            int sendingUser = data.readInt();
             scheduleReceiver(intent, info, compatInfo, resultCode, resultData,
-                    resultExtras, sync);
+                    resultExtras, sync, sendingUser);
             return true;
         }
 
@@ -378,8 +379,9 @@
             Bundle extras = data.readBundle();
             boolean ordered = data.readInt() != 0;
             boolean sticky = data.readInt() != 0;
+            int sendingUser = data.readInt();
             scheduleRegisteredReceiver(receiver, intent,
-                    resultCode, dataStr, extras, ordered, sticky);
+                    resultCode, dataStr, extras, ordered, sticky, sendingUser);
             return true;
         }
 
@@ -755,7 +757,7 @@
     
     public final void scheduleReceiver(Intent intent, ActivityInfo info,
             CompatibilityInfo compatInfo, int resultCode, String resultData,
-            Bundle map, boolean sync) throws RemoteException {
+            Bundle map, boolean sync, int sendingUser) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         intent.writeToParcel(data, 0);
@@ -765,6 +767,7 @@
         data.writeString(resultData);
         data.writeBundle(map);
         data.writeInt(sync ? 1 : 0);
+        data.writeInt(sendingUser);
         mRemote.transact(SCHEDULE_RECEIVER_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -991,8 +994,8 @@
     }
 
     public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
-            int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)
-            throws RemoteException {
+            int resultCode, String dataStr, Bundle extras, boolean ordered,
+            boolean sticky, int sendingUser) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(receiver.asBinder());
@@ -1002,6 +1005,7 @@
         data.writeBundle(extras);
         data.writeInt(ordered ? 1 : 0);
         data.writeInt(sticky ? 1 : 0);
+        data.writeInt(sendingUser);
         mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 232ca07..65ea6a0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -138,6 +138,17 @@
     }
 
     @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        throw new ReceiverCallNotAllowedException(
+                "IntentReceiver components are not allowed to register to receive intents");
+        //ex.fillInStackTrace();
+        //Log.e("IntentReceiver", ex.getMessage(), ex);
+        //return mContext.registerReceiver(receiver, filter, broadcastPermission,
+        //        scheduler);
+    }
+
+    @Override
     public boolean bindService(Intent service, ServiceConnection conn, int flags) {
         throw new ReceiverCallNotAllowedException(
                 "IntentReceiver components are not allowed to bind to services");
@@ -1252,11 +1263,18 @@
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
             String broadcastPermission, Handler scheduler) {
-        return registerReceiverInternal(receiver, filter, broadcastPermission,
-                scheduler, getOuterContext());
+        return registerReceiverInternal(receiver, UserHandle.myUserId(),
+                filter, broadcastPermission, scheduler, getOuterContext());
     }
 
-    private Intent registerReceiverInternal(BroadcastReceiver receiver,
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        return registerReceiverInternal(receiver, user.getIdentifier(),
+                filter, broadcastPermission, scheduler, getOuterContext());
+    }
+
+    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
             IntentFilter filter, String broadcastPermission,
             Handler scheduler, Context context) {
         IIntentReceiver rd = null;
@@ -1279,7 +1297,7 @@
         try {
             return ActivityManagerNative.getDefault().registerReceiver(
                     mMainThread.getApplicationThread(), mBasePackageName,
-                    rd, filter, broadcastPermission);
+                    rd, filter, broadcastPermission, userId);
         } catch (RemoteException e) {
             return null;
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f7c7013..7a633ed 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -80,7 +80,7 @@
     public boolean willActivityBeVisible(IBinder token) throws RemoteException;
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
             IIntentReceiver receiver, IntentFilter filter,
-            String requiredPermission) throws RemoteException;
+            String requiredPermission, int userId) throws RemoteException;
     public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;
     public int broadcastIntent(IApplicationThread caller, Intent intent,
             String resolvedType, IIntentReceiver resultTo, int resultCode,
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f60cfd6..03a26d4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -65,7 +65,8 @@
     void scheduleDestroyActivity(IBinder token, boolean finished,
             int configChanges) throws RemoteException;
     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
-            int resultCode, String data, Bundle extras, boolean sync) throws RemoteException;
+            int resultCode, String data, Bundle extras, boolean sync,
+            int sendingUser) throws RemoteException;
     static final int BACKUP_MODE_INCREMENTAL = 0;
     static final int BACKUP_MODE_FULL = 1;
     static final int BACKUP_MODE_RESTORE = 2;
@@ -105,8 +106,8 @@
     void dumpProvider(FileDescriptor fd, IBinder servicetoken, String[] args)
             throws RemoteException;
     void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
-            int resultCode, String data, Bundle extras, boolean ordered, boolean sticky)
-            throws RemoteException;
+            int resultCode, String data, Bundle extras, boolean ordered,
+            boolean sticky, int sendingUser) throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
     void profilerControl(boolean start, String path, ParcelFileDescriptor fd, int profileType)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 6197b1a..0a9ed58 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -670,8 +670,8 @@
                 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                 mStrongRef = strong ? rd : null;
             }
-            public void performReceive(Intent intent, int resultCode,
-                    String data, Bundle extras, boolean ordered, boolean sticky) {
+            public void performReceive(Intent intent, int resultCode, String data,
+                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
                 if (ActivityThread.DEBUG_BROADCAST) {
                     int seq = intent.getIntExtra("seq", -1);
@@ -680,7 +680,7 @@
                 }
                 if (rd != null) {
                     rd.performReceive(intent, resultCode, data, extras,
-                            ordered, sticky);
+                            ordered, sticky, sendingUser);
                 } else {
                     // The activity manager dispatched a broadcast to a registered
                     // receiver in this process, but before it could be delivered the
@@ -716,10 +716,10 @@
             private final boolean mOrdered;
 
             public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
-                    boolean ordered, boolean sticky) {
+                    boolean ordered, boolean sticky, int sendingUser) {
                 super(resultCode, resultData, resultExtras,
                         mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
-                        ordered, sticky, mIIntentReceiver.asBinder());
+                        ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
                 mCurIntent = intent;
                 mOrdered = ordered;
             }
@@ -830,14 +830,15 @@
             return mUnregisterLocation;
         }
 
-        public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean ordered, boolean sticky) {
+        public void performReceive(Intent intent, int resultCode, String data,
+                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
             if (ActivityThread.DEBUG_BROADCAST) {
                 int seq = intent.getIntExtra("seq", -1);
                 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
                         + " to " + mReceiver);
             }
-            Args args = new Args(intent, resultCode, data, extras, ordered, sticky);
+            Args args = new Args(intent, resultCode, data, extras, ordered,
+                    sticky, sendingUser);
             if (!mActivityThread.post(args)) {
                 if (mRegistered && ordered) {
                     IActivityManager mgr = ActivityManagerNative.getDefault();
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index bcd42ea..a3c1838 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -147,8 +147,8 @@
             mWho = who;
             mHandler = handler;
         }
-        public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean serialized, boolean sticky) {
+        public void performReceive(Intent intent, int resultCode, String data,
+                Bundle extras, boolean serialized, boolean sticky, int sendingUser) {
             mIntent = intent;
             mResultCode = resultCode;
             mResultData = data;
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 1c37414..c8062ca 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -50,23 +50,23 @@
  */
 public final class DeviceAdminInfo implements Parcelable {
     static final String TAG = "DeviceAdminInfo";
-    
+
     /**
      * A type of policy that this device admin can use: limit the passwords
      * that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
      * and {@link DevicePolicyManager#setPasswordMinimumLength}.
-     * 
+     *
      * <p>To control this policy, the device admin must have a "limit-password"
      * tag in the "uses-policies" section of its meta-data.
      */
     public static final int USES_POLICY_LIMIT_PASSWORD = 0;
-    
+
     /**
      * A type of policy that this device admin can use: able to watch login
      * attempts from the user, via {@link DeviceAdminReceiver#ACTION_PASSWORD_FAILED},
      * {@link DeviceAdminReceiver#ACTION_PASSWORD_SUCCEEDED}, and
      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
-     * 
+     *
      * <p>To control this policy, the device admin must have a "watch-login"
      * tag in the "uses-policies" section of its meta-data.
      */
@@ -76,7 +76,7 @@
      * A type of policy that this device admin can use: able to reset the
      * user's password via
      * {@link DevicePolicyManager#resetPassword}.
-     * 
+     *
      * <p>To control this policy, the device admin must have a "reset-password"
      * tag in the "uses-policies" section of its meta-data.
      */
@@ -87,7 +87,7 @@
      * to lock via{@link DevicePolicyManager#lockNow} or limit the
      * maximum lock timeout for the device via
      * {@link DevicePolicyManager#setMaximumTimeToLock}.
-     * 
+     *
      * <p>To control this policy, the device admin must have a "force-lock"
      * tag in the "uses-policies" section of its meta-data.
      */
@@ -97,7 +97,7 @@
      * A type of policy that this device admin can use: able to factory
      * reset the device, erasing all of the user's data, via
      * {@link DevicePolicyManager#wipeData}.
-     * 
+     *
      * <p>To control this policy, the device admin must have a "wipe-data"
      * tag in the "uses-policies" section of its meta-data.
      */
@@ -138,13 +138,21 @@
      */
     public static final int USES_POLICY_DISABLE_CAMERA = 8;
 
+    /**
+     * A type of policy that this device admin can use: disables use of keyguard widgets.
+     *
+     * <p>To control this policy, the device admin must have a "disable-keyguard-widgets"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_DISABLE_KEYGUARD_WIDGETS = 9;
+
     /** @hide */
     public static class PolicyInfo {
         public final int ident;
         final public String tag;
         final public int label;
         final public int description;
-        
+
         public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
             ident = identIn;
             tag = tagIn;
@@ -152,11 +160,11 @@
             description = descriptionIn;
         }
     }
-    
+
     static ArrayList<PolicyInfo> sPoliciesDisplayOrder = new ArrayList<PolicyInfo>();
     static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
     static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
-    
+
     static {
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
                 com.android.internal.R.string.policylab_wipeData,
@@ -185,6 +193,10 @@
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_DISABLE_CAMERA, "disable-camera",
                 com.android.internal.R.string.policylab_disableCamera,
                 com.android.internal.R.string.policydesc_disableCamera));
+        sPoliciesDisplayOrder.add(new PolicyInfo(
+                USES_POLICY_DISABLE_KEYGUARD_WIDGETS, "disable-keyguard-widgets",
+                com.android.internal.R.string.policylab_disableKeyguardWidgets,
+                com.android.internal.R.string.policydesc_disableKeyguardWidgets));
 
         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
@@ -192,25 +204,25 @@
             sKnownPolicies.put(pi.tag, pi.ident);
         }
     }
-    
+
     /**
      * The BroadcastReceiver that implements this device admin component.
      */
     final ResolveInfo mReceiver;
-    
+
     /**
      * Whether this should be visible to the user.
      */
     boolean mVisible;
-    
+
     /**
      * The policies this administrator needs access to.
      */
     int mUsesPolicies;
-    
+
     /**
      * Constructor.
-     * 
+     *
      * @param context The Context in which we are parsing the device admin.
      * @param receiver The ResolveInfo returned from the package manager about
      * this device admin's component.
@@ -219,9 +231,9 @@
             throws XmlPullParserException, IOException {
         mReceiver = receiver;
         ActivityInfo ai = receiver.activityInfo;
-        
+
         PackageManager pm = context.getPackageManager();
-        
+
         XmlResourceParser parser = null;
         try {
             parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
@@ -229,30 +241,30 @@
                 throw new XmlPullParserException("No "
                         + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
             }
-        
+
             Resources res = pm.getResourcesForApplication(ai.applicationInfo);
-            
+
             AttributeSet attrs = Xml.asAttributeSet(parser);
-            
+
             int type;
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                     && type != XmlPullParser.START_TAG) {
             }
-            
+
             String nodeName = parser.getName();
             if (!"device-admin".equals(nodeName)) {
                 throw new XmlPullParserException(
                         "Meta-data does not start with device-admin tag");
             }
-            
+
             TypedArray sa = res.obtainAttributes(attrs,
                     com.android.internal.R.styleable.DeviceAdmin);
 
             mVisible = sa.getBoolean(
                     com.android.internal.R.styleable.DeviceAdmin_visible, true);
-            
+
             sa.recycle();
-            
+
             int outerDepth = parser.getDepth();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -290,14 +302,14 @@
         mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
         mUsesPolicies = source.readInt();
     }
-    
+
     /**
      * Return the .apk package that implements this device admin.
      */
     public String getPackageName() {
         return mReceiver.activityInfo.packageName;
     }
-    
+
     /**
      * Return the class name of the receiver component that implements
      * this device admin.
@@ -321,20 +333,20 @@
         return new ComponentName(mReceiver.activityInfo.packageName,
                 mReceiver.activityInfo.name);
     }
-    
+
     /**
      * Load the user-displayed label for this device admin.
-     * 
+     *
      * @param pm Supply a PackageManager used to load the device admin's
      * resources.
      */
     public CharSequence loadLabel(PackageManager pm) {
         return mReceiver.loadLabel(pm);
     }
-    
+
     /**
      * Load user-visible description associated with this device admin.
-     * 
+     *
      * @param pm Supply a PackageManager used to load the device admin's
      * resources.
      */
@@ -351,17 +363,17 @@
         }
         throw new NotFoundException();
     }
-    
+
     /**
      * Load the user-displayed icon for this device admin.
-     * 
+     *
      * @param pm Supply a PackageManager used to load the device admin's
      * resources.
      */
     public Drawable loadIcon(PackageManager pm) {
         return mReceiver.loadIcon(pm);
     }
-    
+
     /**
      * Returns whether this device admin would like to be visible to the
      * user, even when it is not enabled.
@@ -369,7 +381,7 @@
     public boolean isVisible() {
         return mVisible;
     }
-    
+
     /**
      * Return true if the device admin has requested that it be able to use
      * the given policy control.  The possible policy identifier inputs are:
@@ -382,7 +394,7 @@
     public boolean usesPolicy(int policyIdent) {
         return (mUsesPolicies & (1<<policyIdent)) != 0;
     }
-    
+
     /**
      * Return the XML tag name for the given policy identifier.  Valid identifiers
      * are as per {@link #usesPolicy(int)}.  If the given identifier is not
@@ -391,7 +403,7 @@
     public String getTagForPolicy(int policyIdent) {
         return sRevKnownPolicies.get(policyIdent).tag;
     }
-    
+
     /** @hide */
     public ArrayList<PolicyInfo> getUsedPolicies() {
         ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
@@ -403,25 +415,25 @@
         }
         return res;
     }
-    
+
     /** @hide */
     public void writePoliciesToXml(XmlSerializer out)
             throws IllegalArgumentException, IllegalStateException, IOException {
         out.attribute(null, "flags", Integer.toString(mUsesPolicies));
     }
-    
+
     /** @hide */
     public void readPoliciesFromXml(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         mUsesPolicies = Integer.parseInt(
                 parser.getAttributeValue(null, "flags"));
     }
-    
+
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "Receiver:");
         mReceiver.dump(pw, prefix + "  ");
     }
-    
+
     @Override
     public String toString() {
         return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
@@ -429,7 +441,7 @@
 
     /**
      * Used to package this object into a {@link Parcel}.
-     * 
+     *
      * @param dest The {@link Parcel} to be written.
      * @param flags The flags used for parceling.
      */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0b58396..4c55bb3 100755
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1155,6 +1155,16 @@
             = "android.app.action.START_ENCRYPTION";
 
     /**
+     * Widgets are enabled in keyguard
+     */
+    public static final int KEYGUARD_DISABLE_WIDGETS_NONE = 0;
+
+    /**
+     * Disable all keyguard widgets
+     */
+    public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 0x7fffffff;
+
+    /**
      * Called by an application that is administering the device to
      * request that the storage system be encrypted.
      *
@@ -1284,6 +1294,46 @@
     }
 
     /**
+     * Called by an application that is administering the device to disable adding widgets to
+     * keyguard.  After setting this, keyguard widgets will be disabled according to the state
+     * provided.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_WIDGETS} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param which {@link DevicePolicyManager#KEYGUARD_DISABLE_WIDGETS_ALL} or
+     * {@link DevicePolicyManager#KEYGUARD_DISABLE_WIDGETS_NONE} (the default).
+     */
+    public void setKeyguardWidgetsDisabled(ComponentName admin, int which) {
+        if (mService != null) {
+            try {
+                mService.setKeyguardWidgetsDisabled(admin, which);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Determine whether or not widgets have been disabled in keyguard either by the current
+     * admin, if specified, or all admins.
+     * @param admin The name of the admin component to check, or null to check if any admins
+     * have disabled widgets in keyguard.
+     */
+    public int getKeyguardWidgetsDisabled(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getKeyguardWidgetsDisabled(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return KEYGUARD_DISABLE_WIDGETS_NONE;
+    }
+
+    /**
      * @hide
      */
     public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9419a62..0b7ec122 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -48,7 +48,7 @@
 
     void setPasswordMinimumNonLetter(in ComponentName who, int length);
     int getPasswordMinimumNonLetter(in ComponentName who);
-    
+
     void setPasswordHistoryLength(in ComponentName who, int length);
     int getPasswordHistoryLength(in ComponentName who);
 
@@ -59,17 +59,17 @@
 
     boolean isActivePasswordSufficient();
     int getCurrentFailedPasswordAttempts();
-    
+
     void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
     int getMaximumFailedPasswordsForWipe(in ComponentName admin);
-    
+
     boolean resetPassword(String password, int flags);
-    
+
     void setMaximumTimeToLock(in ComponentName who, long timeMs);
     long getMaximumTimeToLock(in ComponentName who);
-    
+
     void lockNow();
-    
+
     void wipeData(int flags);
 
     ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
@@ -82,6 +82,9 @@
     void setCameraDisabled(in ComponentName who, boolean disabled);
     boolean getCameraDisabled(in ComponentName who);
 
+    void setKeyguardWidgetsDisabled(in ComponentName who, int which);
+    int getKeyguardWidgetsDisabled(in ComponentName who);
+
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing);
     boolean isAdminActive(in ComponentName policyReceiver);
     List<ComponentName> getActiveAdmins();
@@ -89,7 +92,7 @@
     void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
     void removeActiveAdmin(in ComponentName policyReceiver);
     boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy);
-    
+
     void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
         int numbers, int symbols, int nonletter);
     void reportFailedPasswordAttempt();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 446f1af..1500b00 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -237,16 +237,17 @@
         final boolean mOrderedHint;
         final boolean mInitialStickyHint;
         final IBinder mToken;
+        final int mSendingUser;
         
         int mResultCode;
         String mResultData;
         Bundle mResultExtras;
         boolean mAbortBroadcast;
         boolean mFinished;
-        
+
         /** @hide */
         public PendingResult(int resultCode, String resultData, Bundle resultExtras,
-                int type, boolean ordered, boolean sticky, IBinder token) {
+                int type, boolean ordered, boolean sticky, IBinder token, int userId) {
             mResultCode = resultCode;
             mResultData = resultData;
             mResultExtras = resultExtras;
@@ -254,6 +255,7 @@
             mOrderedHint = ordered;
             mInitialStickyHint = sticky;
             mToken = token;
+            mSendingUser = userId;
         }
         
         /**
@@ -425,7 +427,12 @@
                 }
             }
         }
-        
+
+        /** @hide */
+        public int getSendingUserId() {
+            return mSendingUser;
+        }
+
         void checkSynchronousHint() {
             // Note that we don't assert when receiving the initial sticky value,
             // since that may have come from an ordered broadcast.  We'll catch
@@ -733,6 +740,11 @@
         return mPendingResult;
     }
     
+    /** @hide */
+    public int getSendingUserId() {
+        return mPendingResult.mSendingUser;
+    }
+
     /**
      * Control inclusion of debugging help for mismatched
      * calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8a4cb44..7438ba8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1410,9 +1410,35 @@
      * @see #unregisterReceiver
      */
     public abstract Intent registerReceiver(BroadcastReceiver receiver,
-                                            IntentFilter filter,
-                                            String broadcastPermission,
-                                            Handler scheduler);
+            IntentFilter filter, String broadcastPermission, Handler scheduler);
+
+    /**
+     * @hide
+     * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
+     * but for a specific user.  This receiver will receiver broadcasts that
+     * are sent to the requested user.  It
+     * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+     * permission.
+     *
+     * @param receiver The BroadcastReceiver to handle the broadcast.
+     * @param user UserHandle to send the intent to.
+     * @param filter Selects the Intent broadcasts to be received.
+     * @param broadcastPermission String naming a permissions that a
+     *      broadcaster must hold in order to send an Intent to you.  If null,
+     *      no permission is required.
+     * @param scheduler Handler identifying the thread that will receive
+     *      the Intent.  If null, the main thread of the process will be used.
+     *
+     * @return The first sticky intent found that matches <var>filter</var>,
+     *         or null if there are none.
+     *
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler
+     * @see #sendBroadcast
+     * @see #unregisterReceiver
+     */
+    public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver,
+            UserHandle user, IntentFilter filter, String broadcastPermission,
+            Handler scheduler);
 
     /**
      * Unregister a previously registered BroadcastReceiver.  <em>All</em>
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e8c63d6..6101f4e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -425,6 +425,15 @@
                 scheduler);
     }
 
+    /** @hide */
+    @Override
+    public Intent registerReceiverAsUser(
+        BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
+        String broadcastPermission, Handler scheduler) {
+        return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler);
+    }
+
     @Override
     public void unregisterReceiver(BroadcastReceiver receiver) {
         mBase.unregisterReceiver(receiver);
diff --git a/core/java/android/content/IIntentReceiver.aidl b/core/java/android/content/IIntentReceiver.aidl
index 6f2f7c4..3d92723 100755
--- a/core/java/android/content/IIntentReceiver.aidl
+++ b/core/java/android/content/IIntentReceiver.aidl
@@ -27,7 +27,7 @@
  * {@hide}
  */
 oneway interface IIntentReceiver {
-    void performReceive(in Intent intent, int resultCode,
-            String data, in Bundle extras, boolean ordered, boolean sticky);
+    void performReceive(in Intent intent, int resultCode, String data,
+            in Bundle extras, boolean ordered, boolean sticky, int sendingUser);
 }
 
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 079241a..6c3cf99 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -114,8 +114,8 @@
             mWho = who;
             mHandler = handler;
         }
-        public void performReceive(Intent intent, int resultCode,
-                String data, Bundle extras, boolean serialized, boolean sticky) {
+        public void performReceive(Intent intent, int resultCode, String data,
+                Bundle extras, boolean serialized, boolean sticky, int sendingUser) {
             mIntent = intent;
             mResultCode = resultCode;
             mResultData = data;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 3035729..0b320f0 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -372,6 +372,12 @@
     public static final int CONFIG_DENSITY = 0x1000;
     /**
      * Bit in {@link #configChanges} that indicates that the activity
+     * can itself handle the change to layout direction. Set from the
+     * {@link android.R.attr#configChanges} attribute.
+     */
+    public static final int CONFIG_LAYOUT_DIRECTION = 0x2000;
+    /**
+     * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle changes to the font scaling factor.  Set from the
      * {@link android.R.attr#configChanges} attribute.  This is
      * not a core resource configutation, but a higher-level value, so its
@@ -398,6 +404,7 @@
         0x0200, // SCREEN SIZE
         0x2000, // SMALLEST SCREEN SIZE
         0x0100, // DENSITY
+        0x4000, // LAYOUT DIRECTION
     };
     /** @hide
      * Convert Java change bits to native.
@@ -434,8 +441,9 @@
      * {@link #CONFIG_MCC}, {@link #CONFIG_MNC},
      * {@link #CONFIG_LOCALE}, {@link #CONFIG_TOUCHSCREEN},
      * {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION},
-     * {@link #CONFIG_ORIENTATION}, and {@link #CONFIG_SCREEN_LAYOUT}.  Set from the
-     * {@link android.R.attr#configChanges} attribute.
+     * {@link #CONFIG_ORIENTATION}, {@link #CONFIG_SCREEN_LAYOUT} and
+     * {@link #CONFIG_LAYOUT_DIRECTION}.  Set from the {@link android.R.attr#configChanges}
+     * attribute.
      */
     public int configChanges;
     
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 52b6498..0b77842 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -125,7 +125,25 @@
      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
      * resource qualifier. */
     public static final int SCREENLAYOUT_LONG_YES = 0x20;
-    
+
+    /** Constant for {@link #screenLayout}: bits that encode the layout direction. */
+    public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
+    /** Constant for {@link #screenLayout}: bits shift to get the layout direction. */
+    public static final int SCREENLAYOUT_LAYOUTDIR_SHIFT = 6;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
+     * value indicating that no layout dir has been set. */
+    public static final int SCREENLAYOUT_LAYOUTDIR_UNDEFINED = 0x00;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
+     * value indicating that a layout dir has been set to LTR. */
+    public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_LAYOUTDIR_MASK}
+     * value indicating that a layout dir has been set to RTL. */
+    public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
+
+    /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */
+    public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED |
+            SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED;
+
     /**
      * Special flag we generate to indicate that the screen layout requires
      * us to use a compatibility mode for apps that are not modern layout
@@ -146,6 +164,10 @@
      * is wider/taller than normal.  They may be one of
      * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
      * 
+     * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
+     * is either LTR or RTL.  They may be one of
+     * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.
+     *
      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
      * Multiple Screens</a> for more information.
      */
@@ -442,11 +464,6 @@
     public int compatSmallestScreenWidthDp;
 
     /**
-     * @hide The layout direction associated to the current Locale
-     */
-    public int layoutDirection;
-
-    /**
      * @hide Internal book-keeping.
      */
     public int seq;
@@ -472,7 +489,6 @@
         mnc = o.mnc;
         if (o.locale != null) {
             locale = (Locale) o.locale.clone();
-            layoutDirection = o.layoutDirection;
         }
         userSetLocale = o.userSetLocale;
         touchscreen = o.touchscreen;
@@ -517,10 +533,13 @@
         } else {
             sb.append(" ?locale");
         }
-        switch (layoutDirection) {
-            case View.LAYOUT_DIRECTION_LTR: /* ltr not interesting */ break;
-            case View.LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break;
-            default: sb.append(" layoutDir="); sb.append(layoutDirection); break;
+        int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
+        switch (layoutDir) {
+            case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
+            case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ltr"); break;
+            case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" rtl"); break;
+            default: sb.append(" layoutDir=");
+                sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
         }
         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
@@ -643,13 +662,12 @@
         navigation = NAVIGATION_UNDEFINED;
         navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
         orientation = ORIENTATION_UNDEFINED;
-        screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
+        screenLayout = SCREENLAYOUT_UNDEFINED;
         uiMode = UI_MODE_TYPE_UNDEFINED;
         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
         densityDpi = DENSITY_DPI_UNDEFINED;
-        layoutDirection = View.LAYOUT_DIRECTION_LTR;
         seq = 0;
     }
 
@@ -685,7 +703,11 @@
             changed |= ActivityInfo.CONFIG_LOCALE;
             locale = delta.locale != null
                     ? (Locale) delta.locale.clone() : null;
-            layoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
+            // If locale has changed, then layout direction is also changed ...
+            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+            // ... and we need to update the layout direction (represented by the first
+            // 2 most significant bits in screenLayout).
+            setLayoutDirection(locale);
         }
         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
         {
@@ -727,10 +749,17 @@
             changed |= ActivityInfo.CONFIG_ORIENTATION;
             orientation = delta.orientation;
         }
-        if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
-                && screenLayout != delta.screenLayout) {
+        if (getScreenLayoutNoDirection(delta.screenLayout) !=
+                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
+                && (getScreenLayoutNoDirection(screenLayout) !=
+                    getScreenLayoutNoDirection(delta.screenLayout))) {
             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
-            screenLayout = delta.screenLayout;
+            // We need to preserve the previous layout dir bits if they were defined
+            if ((delta.screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == 0) {
+                screenLayout = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK)|delta.screenLayout;
+            } else {
+                screenLayout = delta.screenLayout;
+            }
         }
         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
                 && uiMode != delta.uiMode) {
@@ -771,7 +800,6 @@
         if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
         }
-        
         if (delta.seq != 0) {
             seq = delta.seq;
         }
@@ -807,6 +835,8 @@
      * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or
      * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE
      * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}.
+     * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION
+     * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}.
      */
     public int diff(Configuration delta) {
         int changed = 0;
@@ -822,6 +852,7 @@
         if (delta.locale != null
                 && (locale == null || !locale.equals(delta.locale))) {
             changed |= ActivityInfo.CONFIG_LOCALE;
+            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
                 && touchscreen != delta.touchscreen) {
@@ -851,8 +882,10 @@
                 && orientation != delta.orientation) {
             changed |= ActivityInfo.CONFIG_ORIENTATION;
         }
-        if (delta.screenLayout != SCREENLAYOUT_SIZE_UNDEFINED
-                && screenLayout != delta.screenLayout) {
+        if (getScreenLayoutNoDirection(delta.screenLayout) !=
+                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
+                && getScreenLayoutNoDirection(screenLayout) !=
+                    getScreenLayoutNoDirection(delta.screenLayout)) {
             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
         }
         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
@@ -875,7 +908,7 @@
                 && densityDpi != delta.densityDpi) {
             changed |= ActivityInfo.CONFIG_DENSITY;
         }
-        
+
         return changed;
     }
 
@@ -963,7 +996,6 @@
         dest.writeInt(compatScreenWidthDp);
         dest.writeInt(compatScreenHeightDp);
         dest.writeInt(compatSmallestScreenWidthDp);
-        dest.writeInt(layoutDirection);
         dest.writeInt(seq);
     }
 
@@ -992,7 +1024,6 @@
         compatScreenWidthDp = source.readInt();
         compatScreenHeightDp = source.readInt();
         compatSmallestScreenWidthDp = source.readInt();
-        layoutDirection = source.readInt();
         seq = source.readInt();
     }
     
@@ -1100,4 +1131,50 @@
         result = 31 * result + densityDpi;
         return result;
     }
+
+    /**
+     * Set the locale. This is the preferred way for setting up the locale (instead of using the
+     * direct accessor). This will also set the userLocale and layout direction according to
+     * the locale.
+     *
+     * @param loc The locale. Can be null.
+     */
+    public void setLocale(Locale loc) {
+        locale = loc;
+        userSetLocale = true;
+        setLayoutDirection(locale);
+    }
+
+    /**
+     * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
+     * {@link View#LAYOUT_DIRECTION_RTL}.
+     *
+     * @return the layout direction
+     */
+    public int getLayoutDirection() {
+        // We need to substract one here as the configuration values are using "0" as undefined thus
+        // having LRT set to "1" and RTL set to "2"
+        return ((screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) >> SCREENLAYOUT_LAYOUTDIR_SHIFT) - 1;
+    }
+
+    /**
+     * Set the layout direction from the Locale.
+     *
+     * @param locale The Locale. If null will set the layout direction to
+     * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
+     * corresponding to the Locale.
+     *
+     * @see {@link View#LAYOUT_DIRECTION_LTR} and {@link View#LAYOUT_DIRECTION_RTL}
+     */
+    public void setLayoutDirection(Locale locale) {
+        // There is a "1" difference between the configuration values for
+        // layout direction and View constants for layout direction, just add "1".
+        final int layoutDirection = 1 + LocaleUtil.getLayoutDirectionFromLocale(locale);
+        screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
+                (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
+    }
+
+    private static int getScreenLayoutNoDirection(int screenLayout) {
+        return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
+    }
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7559f1e..42a6bdc 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1444,12 +1444,14 @@
                 }
                 if (mTmpConfig.locale == null) {
                     mTmpConfig.locale = Locale.getDefault();
+                    mTmpConfig.setLayoutDirection(mTmpConfig.locale);
                 }
                 configChanges = mConfiguration.updateFrom(mTmpConfig);
                 configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
             }
             if (mConfiguration.locale == null) {
                 mConfiguration.locale = Locale.getDefault();
+                mConfiguration.setLayoutDirection(mConfiguration.locale);
             }
             if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
                 mMetrics.densityDpi = mConfiguration.densityDpi;
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index dc36088..bcb8800 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -86,8 +86,8 @@
          * pointers going up.
          *
          * Once a scale has ended, {@link ScaleGestureDetector#getFocusX()}
-         * and {@link ScaleGestureDetector#getFocusY()} will return the location
-         * of the pointer remaining on the screen.
+         * and {@link ScaleGestureDetector#getFocusY()} will return focal point
+         * of the pointers remaining on the screen.
          *
          * @param detector The detector reporting the event - use this to
          *          retrieve extended info about event state.
@@ -128,6 +128,7 @@
 
     private float mCurrSpan;
     private float mPrevSpan;
+    private float mInitialSpan;
     private float mCurrSpanX;
     private float mCurrSpanY;
     private float mPrevSpanX;
@@ -135,6 +136,7 @@
     private long mCurrTime;
     private long mPrevTime;
     private boolean mInProgress;
+    private int mSpanSlop;
 
     /**
      * Consistency verifier for debugging purposes.
@@ -146,6 +148,7 @@
     public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
         mContext = context;
         mListener = listener;
+        mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
     }
 
     /**
@@ -176,6 +179,7 @@
             if (mInProgress) {
                 mListener.onScaleEnd(this);
                 mInProgress = false;
+                mInitialSpan = 0;
             }
 
             if (streamComplete) {
@@ -221,18 +225,24 @@
         // Dispatch begin/end events as needed.
         // If the configuration changes, notify the app to reset its current state by beginning
         // a fresh scale event stream.
+        final boolean wasInProgress = mInProgress;
+        mFocusX = focusX;
+        mFocusY = focusY;
         if (mInProgress && (span == 0 || configChanged)) {
             mListener.onScaleEnd(this);
             mInProgress = false;
+            mInitialSpan = span;
         }
         if (configChanged) {
             mPrevSpanX = mCurrSpanX = spanX;
             mPrevSpanY = mCurrSpanY = spanY;
-            mPrevSpan = mCurrSpan = span;
+            mInitialSpan = mPrevSpan = mCurrSpan = span;
         }
-        if (!mInProgress && span != 0) {
-            mFocusX = focusX;
-            mFocusY = focusY;
+        if (!mInProgress && span != 0 &&
+                (wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
+            mPrevSpanX = mCurrSpanX = spanX;
+            mPrevSpanY = mCurrSpanY = spanY;
+            mPrevSpan = mCurrSpan = span;
             mInProgress = mListener.onScaleBegin(this);
         }
 
@@ -241,8 +251,6 @@
             mCurrSpanX = spanX;
             mCurrSpanY = spanY;
             mCurrSpan = span;
-            mFocusX = focusX;
-            mFocusY = focusY;
 
             boolean updatePrev = true;
             if (mInProgress) {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6616894..db05e10 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -262,12 +262,8 @@
             IBinder displayToken, SurfaceTexture surfaceTexture);
     private static native void nativeSetDisplayLayerStack(
             IBinder displayToken, int layerStack);
-    private static native void nativeSetDisplayOrientation(
-            IBinder displayToken, int orientation);
-    private static native void nativeSetDisplayViewport(
-            IBinder displayToken, Rect viewport);
-    private static native void nativeSetDisplayFrame(
-            IBinder displayToken, Rect frame);
+    private static native void nativeSetDisplayProjection(
+            IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect);
     private static native boolean nativeGetDisplayInfo(
             IBinder displayToken, PhysicalDisplayInfo outInfo);
 
@@ -617,33 +613,18 @@
     }
 
     /** @hide */
-    public static void setDisplayOrientation(IBinder displayToken, int orientation) {
+    public static void setDisplayProjection(IBinder displayToken,
+            int orientation, Rect layerStackRect, Rect displayRect) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
-        nativeSetDisplayOrientation(displayToken, orientation);
-    }
-
-    /** @hide */
-    public static void setDisplayViewport(IBinder displayToken, Rect viewport) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
+        if (layerStackRect == null) {
+            throw new IllegalArgumentException("layerStackRect must not be null");
         }
-        if (viewport == null) {
-            throw new IllegalArgumentException("viewport must not be null");
+        if (displayRect == null) {
+            throw new IllegalArgumentException("displayRect must not be null");
         }
-        nativeSetDisplayViewport(displayToken, viewport);
-    }
-
-    /** @hide */
-    public static void setDisplayFrame(IBinder displayToken, Rect frame) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        if (frame == null) {
-            throw new IllegalArgumentException("frame must not be null");
-        }
-        nativeSetDisplayFrame(displayToken, frame);
+        nativeSetDisplayProjection(displayToken, orientation, layerStackRect, displayRect);
     }
 
     /** @hide */
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 131f0ae..08e30aa 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -34,6 +34,7 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Printer;
+import android.util.Slog;
 import android.util.Xml;
 
 import java.io.IOException;
@@ -169,7 +170,10 @@
                             a.getBoolean(com.android.internal.R.styleable
                                     .InputMethod_Subtype_isAuxiliary, false),
                             a.getBoolean(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false));
+                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false),
+                            a.getInt(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */)
+                            );
                     if (!subtype.isAuxiliary()) {
                         mIsAuxIme = false;
                     }
@@ -194,6 +198,9 @@
                 final InputMethodSubtype subtype = additionalSubtypes.get(i);
                 if (!mSubtypes.contains(subtype)) {
                     mSubtypes.add(subtype);
+                } else {
+                    Slog.w(TAG, "Duplicated subtype definition found: "
+                            + subtype.getLocale() + ", " + subtype.getMode());
                 }
             }
         }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index b7c94a3..7895e6f 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -55,13 +55,14 @@
     private final int mSubtypeHashCode;
     private final int mSubtypeIconResId;
     private final int mSubtypeNameResId;
+    private final int mSubtypeId;
     private final String mSubtypeLocale;
     private final String mSubtypeMode;
     private final String mSubtypeExtraValue;
     private volatile HashMap<String, String> mExtraValueHashMapCache;
 
     /**
-     * Constructor.
+     * Constructor with no subtype ID specified, overridesImplicitlyEnabledSubtype not specified.
      * @param nameId Resource ID of the subtype name string. The string resource may have exactly
      * one %s in it. If there is, the %s part will be replaced with the locale's display name by
      * the formatter. Please refer to {@link #getDisplayName} for details.
@@ -87,7 +88,7 @@
     }
 
     /**
-     * Constructor.
+     * Constructor with no subtype ID specified.
      * @param nameId Resource ID of the subtype name string. The string resource may have exactly
      * one %s in it. If there is, the %s part will be replaced with the locale's display name by
      * the formatter. Please refer to {@link #getDisplayName} for details.
@@ -112,6 +113,41 @@
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+        this(nameId, iconId, locale, mode, extraValue, isAuxiliary,
+                overridesImplicitlyEnabledSubtype, 0);
+    }
+
+    /**
+     * Constructor.
+     * @param nameId Resource ID of the subtype name string. The string resource may have exactly
+     * one %s in it. If there is, the %s part will be replaced with the locale's display name by
+     * the formatter. Please refer to {@link #getDisplayName} for details.
+     * @param iconId Resource ID of the subtype icon drawable.
+     * @param locale The locale supported by the subtype
+     * @param mode The mode supported by the subtype
+     * @param extraValue The extra value of the subtype. This string is free-form, but the API
+     * supplies tools to deal with a key-value comma-separated list; see
+     * {@link #containsExtraValueKey} and {@link #getExtraValueOf}.
+     * @param isAuxiliary true when this subtype is auxiliary, false otherwise. An auxiliary
+     * subtype will not be shown in the list of enabled IMEs for choosing the current IME in
+     * the Settings even when this subtype is enabled. Please note that this subtype will still
+     * be shown in the list of IMEs in the IME switcher to allow the user to tentatively switch
+     * to this subtype while an IME is shown. The framework will never switch the current IME to
+     * this subtype by {@link android.view.inputmethod.InputMethodManager#switchToLastInputMethod}.
+     * The intent of having this flag is to allow for IMEs that are invoked in a one-shot way as
+     * auxiliary input mode, and return to the previous IME once it is finished (e.g. voice input).
+     * @param overridesImplicitlyEnabledSubtype true when this subtype should be enabled by default
+     * if no other subtypes in the IME are enabled explicitly. Note that a subtype with this
+     * parameter being true will not be shown in the list of subtypes in each IME's subtype enabler.
+     * Having an "automatic" subtype is an example use of this flag.
+     * @param id The unique ID for the subtype. The input method framework keeps track of enabled
+     * subtypes by ID. When the IME package gets upgraded, enabled IDs will stay enabled even if
+     * other attributes are different. If the ID is unspecified or 0,
+     * Arrays.hashCode(new Object[] {locale, mode, extraValue,
+     * isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead.
+     */
+    public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
+            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id) {
         mSubtypeNameResId = nameId;
         mSubtypeIconResId = iconId;
         mSubtypeLocale = locale != null ? locale : "";
@@ -119,8 +155,11 @@
         mSubtypeExtraValue = extraValue != null ? extraValue : "";
         mIsAuxiliary = isAuxiliary;
         mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
-        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
-                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+        // If hashCode() of this subtype is 0 and you want to specify it as an id of this subtype,
+        // just specify 0 as this subtype's id. Then, this subtype's id is treated as 0.
+        mSubtypeHashCode = id != 0 ? id : hashCodeInternal(mSubtypeLocale, mSubtypeMode,
+                mSubtypeExtraValue, mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+        mSubtypeId = id;
     }
 
     InputMethodSubtype(Parcel source) {
@@ -135,8 +174,8 @@
         mSubtypeExtraValue = s != null ? s : "";
         mIsAuxiliary = (source.readInt() == 1);
         mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
-        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
-                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+        mSubtypeHashCode = source.readInt();
+        mSubtypeId = source.readInt();
     }
 
     /**
@@ -288,6 +327,9 @@
     public boolean equals(Object o) {
         if (o instanceof InputMethodSubtype) {
             InputMethodSubtype subtype = (InputMethodSubtype) o;
+            if (subtype.mSubtypeId != 0 || mSubtypeId != 0) {
+                return (subtype.hashCode() == hashCode());
+            }
             return (subtype.hashCode() == hashCode())
                 && (subtype.getNameResId() == getNameResId())
                 && (subtype.getMode().equals(getMode()))
@@ -313,6 +355,8 @@
         dest.writeString(mSubtypeExtraValue);
         dest.writeInt(mIsAuxiliary ? 1 : 0);
         dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
+        dest.writeInt(mSubtypeHashCode);
+        dest.writeInt(mSubtypeId);
     }
 
     public static final Parcelable.Creator<InputMethodSubtype> CREATOR
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 591b87f..9334036 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1346,20 +1346,40 @@
 
     private void onHandleUiTouchEvent(MotionEvent ev) {
         final ScaleGestureDetector detector =
-                mZoomManager.getMultiTouchGestureDetector();
+                mZoomManager.getScaleGestureDetector();
 
-        float x = ev.getX();
-        float y = ev.getY();
+        int action = ev.getActionMasked();
+        final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+        final boolean configChanged =
+            action == MotionEvent.ACTION_POINTER_UP ||
+            action == MotionEvent.ACTION_POINTER_DOWN;
+        final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
+
+        // Determine focal point
+        float sumX = 0, sumY = 0;
+        final int count = ev.getPointerCount();
+        for (int i = 0; i < count; i++) {
+            if (skipIndex == i) continue;
+            sumX += ev.getX(i);
+            sumY += ev.getY(i);
+        }
+        final int div = pointerUp ? count - 1 : count;
+        float x = sumX / div;
+        float y = sumY / div;
+
+        if (configChanged) {
+            mLastTouchX = Math.round(x);
+            mLastTouchY = Math.round(y);
+            mLastTouchTime = ev.getEventTime();
+            mWebView.cancelLongPress();
+            mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+        }
 
         if (detector != null) {
             detector.onTouchEvent(ev);
             if (detector.isInProgress()) {
                 mLastTouchTime = ev.getEventTime();
-                x = detector.getFocusX();
-                y = detector.getFocusY();
 
-                mWebView.cancelLongPress();
-                mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
                 if (!mZoomManager.supportsPanDuringZoom()) {
                     return;
                 }
@@ -1370,14 +1390,9 @@
             }
         }
 
-        int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_POINTER_DOWN) {
             cancelTouch();
             action = MotionEvent.ACTION_DOWN;
-        } else if (action == MotionEvent.ACTION_POINTER_UP) {
-            // set mLastTouchX/Y to the remaining points for multi-touch.
-            mLastTouchX = Math.round(x);
-            mLastTouchY = Math.round(y);
         } else if (action == MotionEvent.ACTION_MOVE) {
             // negative x or y indicate it is on the edge, skip it.
             if (x < 0 || y < 0) {
@@ -4385,7 +4400,7 @@
 
         // A multi-finger gesture can look like a long press; make sure we don't take
         // long press actions if we're scaling.
-        final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+        final ScaleGestureDetector detector = mZoomManager.getScaleGestureDetector();
         if (detector != null && detector.isInProgress()) {
             return false;
         }
@@ -5823,7 +5838,7 @@
     * and the middle point for multi-touch.
     */
     private void handleTouchEventCommon(MotionEvent event, int action, int x, int y) {
-        ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+        ScaleGestureDetector detector = mZoomManager.getScaleGestureDetector();
 
         long eventTime = event.getEventTime();
 
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 8830119..80a6782 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -204,7 +204,7 @@
      */
     private boolean mAllowPanAndScale;
 
-    // use the framework's ScaleGestureDetector to handle multi-touch
+    // use the framework's ScaleGestureDetector to handle scaling gestures
     private ScaleGestureDetector mScaleDetector;
     private boolean mPinchToZoomAnimating = false;
 
@@ -768,7 +768,7 @@
         return isZoomAnimating();
     }
 
-    public ScaleGestureDetector getMultiTouchGestureDetector() {
+    public ScaleGestureDetector getScaleGestureDetector() {
         return mScaleDetector;
     }
 
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index a30567f..9b62a51 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1517,6 +1517,9 @@
         // because the voice search activity will always need to insert "QUERY" into
         // it anyway.
         Bundle queryExtras = new Bundle();
+        if (mAppSearchData != null) {
+            queryExtras.putParcelable(SearchManager.APP_DATA, mAppSearchData);
+        }
 
         // Now build the intent to launch the voice search.  Add all necessary
         // extras to launch the voice recognizer, and then all the necessary extras
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index e8bf9d9..485bd37 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -379,7 +379,7 @@
                 // We can resolve the Gravity here by using the Locale for getting
                 // the layout direction
                 final Configuration config = mView.getContext().getResources().getConfiguration();
-                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.layoutDirection);
+                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
                 mParams.gravity = gravity;
                 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
                     mParams.horizontalWeight = 1.0f;
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 7d1231e..f173327 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -243,10 +243,9 @@
             IActivityManager am = ActivityManagerNative.getDefault();
             Configuration config = am.getConfiguration();
 
-            config.locale = locale;
-
-            // indicate this isn't some passing default - the user wants this remembered
-            config.userSetLocale = true;
+            // Will set userSetLocale to indicate this isn't some passing default - the user
+            // wants this remembered
+            config.setLocale(locale);
 
             am.updateConfiguration(config);
             // Trigger the dirty bit for the Settings Provider.
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4d5e680..4fbfab6 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -647,38 +647,24 @@
     SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
 }
 
-static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jint orientation) {
+static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jint orientation, jobject rect1Obj, jobject rect2Obj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    SurfaceComposerClient::setDisplayOrientation(token, orientation);
-}
+    Rect rect1;
+    rect1.left = env->GetIntField(rect1Obj, gRectClassInfo.left);
+    rect1.top = env->GetIntField(rect1Obj, gRectClassInfo.top);
+    rect1.right = env->GetIntField(rect1Obj, gRectClassInfo.right);
+    rect1.bottom = env->GetIntField(rect1Obj, gRectClassInfo.bottom);
 
-static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject rectObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
+    Rect rect2;
+    rect2.left = env->GetIntField(rect2Obj, gRectClassInfo.left);
+    rect2.top = env->GetIntField(rect2Obj, gRectClassInfo.top);
+    rect2.right = env->GetIntField(rect2Obj, gRectClassInfo.right);
+    rect2.bottom = env->GetIntField(rect2Obj, gRectClassInfo.bottom);
 
-    Rect rect;
-    rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
-    rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
-    rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
-    rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
-    SurfaceComposerClient::setDisplayViewport(token, rect);
-}
-
-static void nativeSetDisplayFrame(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject rectObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    Rect rect;
-    rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
-    rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
-    rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
-    rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
-    SurfaceComposerClient::setDisplayFrame(token, rect);
+    SurfaceComposerClient::setDisplayProjection(token, orientation, rect1, rect2);
 }
 
 static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
@@ -818,12 +804,8 @@
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplayLayerStack },
-    {"nativeSetDisplayOrientation", "(Landroid/os/IBinder;I)V",
-            (void*)nativeSetDisplayOrientation },
-    {"nativeSetDisplayViewport", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
-            (void*)nativeSetDisplayViewport },
-    {"nativeSetDisplayFrame", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
-            (void*)nativeSetDisplayFrame },
+    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;ILandroid/graphics/Rect;Landroid/graphics/Rect;)V",
+            (void*)nativeSetDisplayProjection },
     {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
             (void*)nativeGetDisplayInfo },
     {"nativeCopyFrom", "(Landroid/view/Surface;)V",
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
index df999f0..c6ddd1b 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
@@ -109,7 +109,7 @@
         />
 
     <TextView
-        android:id="@+id/propertyOf"
+        android:id="@+id/owner_info"
         android:lineSpacingExtra="8dip"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
index 565785b..765dc95 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
@@ -109,7 +109,7 @@
         />
 
     <TextView
-        android:id="@+id/propertyOf"
+        android:id="@+id/owner_info"
         android:lineSpacingExtra="8dip"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/core/res/res/layout/keyguard_navigation.xml b/core/res/res/layout/keyguard_navigation.xml
index f9e3ef8..a033101 100644
--- a/core/res/res/layout/keyguard_navigation.xml
+++ b/core/res/res/layout/keyguard_navigation.xml
@@ -31,11 +31,11 @@
         android:padding="10dip"
         android:clickable="true">
 
-        <TextView
-            android:layout_width="20dip"
-            android:layout_height="wrap_content"
-            android:textSize="28dp"
-            android:text="@string/kg_temp_back_string" />
+        <ImageView
+               android:src="?android:attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|start"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"/>
 
         <!-- message area for security screen -->
         <TextView
@@ -43,6 +43,7 @@
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="1"
+            android:layout_gravity="end"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:layout_marginEnd="6dip"
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
index f8d05b7..37e6779 100644
--- a/core/res/res/layout/keyguard_status_view.xml
+++ b/core/res/res/layout/keyguard_status_view.xml
@@ -94,7 +94,7 @@
         </LinearLayout>
 
         <TextView
-            android:id="@*android:id/status1"
+            android:id="@+id/status1"
             android:layout_gravity="end"
             android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
             android:singleLine="true"
@@ -105,7 +105,18 @@
             />
 
         <TextView
-            android:id="@*android:id/carrier"
+            android:id="@+id/owner_info"
+            android:layout_gravity="end"
+            android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+            android:drawablePadding="4dip"
+            />
+
+        <TextView
+            android:id="@+id/carrier"
             android:layout_gravity="end"
             android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
             android:singleLine="true"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4f67789..2eaf87a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -547,6 +547,10 @@
     <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>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Laat die program toe om die inhoud van die interne mediaberging te verander."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"lees die kaslêerstelsel"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Laat die program toe om die kaslêerstelsel te lees en skryf."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"maak/ontvang internetoproepe"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Raak om die netwerk te bestuur."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN se fout"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Raak om verbinding terug te stel"</string>
     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
     <string name="reset" msgid="2448168080964209908">"Stel terug"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b85ad6a..bbe666a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘቶችን ቀይር/ሰርዝ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘትን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"የመሸጎጫ ስርዓተ ፋይል ድረስ"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"መሸጎጫ ስርዓተ ፋይል ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"የበይነ መረብ ጥሪዎች አድርግ/ተቀበል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bf00a81..9b44dcd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"للسماح للتطبيق بالكتابة إلى بطاقة SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تعديل/حذف محتويات وحدة تخزين الوسائط الداخلية"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"للسماح للتطبيق بتعديل محتويات وحدة تخزين الوسائط الداخلية."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"الدخول إلى نظام ملفات ذاكرة التخزين المؤقت"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"للسماح للتطبيق بقراءة نظام ملفات ذاكرة التخزين المؤقت والكتابة به."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"إجراء/تلقي مكالمات عبر الإنترنت"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. المس لإدارة الشبكة."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"المس لإعادة تعيين الاتصال"</string>
     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
     <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 04053f6..7d8c3f3 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змяніць/выдаліць унутраныя носьбіты змесціва"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранай памяці."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"доступ да файлавай сістэмы кэша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанню счытваць і выконваць запіс у файлавую сістэму кэш-памяці."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"рабіць/прымаць iнтэрнэт-выклікі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0813df0..85a2c9e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Разрешава на приложението да записва върху SD картата."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"пром./изтр. на съдърж. на вътр. мултим. хранил."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Разрешава на приложението да променя съдържанието на вътрешното мултимедийно хранилище."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"достъп до файловата система на кеша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Разрешава на приложението да чете и записва във файловата система на кеша."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"извършване/получаване на интернет обаждания"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Свързана със: <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Установява се връзка с винаги включената виртуална частна мрежа (VPN)…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Установена е връзка с винаги включената виртуална частна мрежа (VPN)"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Докоснете, за да възстановите връзката"</string>
     <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5924751..86c9f36 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet a l\'aplicació escriure a la targeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Canvia/esborra emmagatz. intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet que l\'aplicació modifiqui el contingut de l\'emmagatzematge multimèdia intern."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accedir al sistema de fitxers de la memòria cau"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permet que l\'aplicació llegeixi el sistema de fitxers de la memòria cau i que hi escrigui."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fer/rebre trucades per Internet"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 9395aec..5264a43 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikaci zapisovat na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Upravit/smazat interní úlož."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikaci upravovat obsah interního úložiště médií."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"přistupovat do souborového systému mezipaměti"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Umožňuje aplikaci číst a zapisovat do souborového systému mezipaměti."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"uskutečňovat a přijímat internetové hovory"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Dotykem můžete síť spravovat."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Klepnutím resetujete připojení"</string>
     <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
     <string name="reset" msgid="2448168080964209908">"Resetovat"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 050eca8..0aeef97 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillader, at appen kan skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Rediger/slet internt medielagringsindhold"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillader, appen kan ændre indholdet af det interne medielager."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"få adgang til cache-filsystemet"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Tillader, at appen kan læse og skrive i cachefilsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"foretage/modtage internetopkald"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4fdc411..8b1e8bd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ermöglicht der App, auf die SD-Karte zu schreiben"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Intern. Mediensp. änd./löschen"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ermöglicht der App, den Inhalt des internen Medienspeichers zu ändern"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ermöglicht der App Lese- und Schreibzugriff auf das Cache-Dateisystem"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 181dc3f..a299dab 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Επιτρέπει στην εφαρμογή την εγγραφή στην κάρτα SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"τροπ./διαγ. περ. απ. εσ. μνήμ."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Επιτρέπει στην εφαρμογή να τροποποιήσει τα περιεχόμενα των εσωτερικών μέσων αποθήκευσης."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"πρόσβαση στο σύστημα αρχείων προσωρινής μνήμης"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή του συστήματος αρχείων προσωρινής μνήμης."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"πραγματοποίηση/λήψη κλήσεων μέσω Διαδικτύου"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 2dd96c7..2d96b9a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Allows the app to write to the SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modify/delete internal media storage contents"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Allows the app to modify the contents of the internal media storage."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"access the cache file system"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Allows the app to read and write the cache file system."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"make/receive Internet calls"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3e9694c..bd41ffc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Admite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/eliminar los contenidos del almacenamientos de medios internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento de medios interno."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Acceder al sistema de archivos caché"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que la aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"realizar o recibir llamadas por Internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con VPN activada ininterrumpidamente..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN activada ininterrumpidamente."</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN activada ininterrumpidamente."</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca para restablecer la conexión."</string>
     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 32f7e8d..c962de0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento multimedia interno."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que la aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"realizar/recibir llamadas por Internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca para restablecer la conexión."</string>
     <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 32f6ade..d8a0ec5 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Võimaldab rakendusel kirjutada SD-kaardile."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sisemälu sisu muutm./kustut."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Võimaldab rakendusel muuta sisemise andmekandja sisu."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"juurdepääs vahemälu failisüsteemile"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Võimaldab rakendusel vahemälu failisüsteemi lugeda ja kirjutada."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Interneti-kõnede tegemine/vastuvõtmine"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Võrgu haldamiseks puudutage."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati see VPN-i viga"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Ühenduse lähtestamiseks puudutage"</string>
     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a466354..fb9a1ff 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -85,7 +85,7 @@
     <string name="serviceClassFAX" msgid="5566624998840486475">"نمابر"</string>
     <string name="serviceClassSMS" msgid="2015460373701527489">"پیامک"</string>
     <string name="serviceClassDataAsync" msgid="4523454783498551468">"غیر همگام"</string>
-    <string name="serviceClassDataSync" msgid="7530000519646054776">"همگام سازی"</string>
+    <string name="serviceClassDataSync" msgid="7530000519646054776">"همگام‌سازی"</string>
     <string name="serviceClassPacket" msgid="6991006557993423453">"بسته"</string>
     <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
     <string name="roamingText0" msgid="7170335472198694945">"نشانگر رومینگ روشن"</string>
@@ -126,8 +126,8 @@
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"فایل درخواستی پیدا نشد."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"درخواست‌های زیادی در حال پردازش است. بعداً دوباره امتحان کنید."</string>
     <string name="notification_title" msgid="8967710025036163822">"خطای ورود به سیستم برای <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
-    <string name="contentServiceSync" msgid="8353523060269335667">"همگام سازی"</string>
-    <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"همگام سازی"</string>
+    <string name="contentServiceSync" msgid="8353523060269335667">"همگام‌سازی"</string>
+    <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"همگام‌سازی"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"حافظه رایانهٔ لوحی پر است! برخی از فایل‎ها را حذف کنید تا فضا آزاد شود."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایل‌ها را حذف کنید تا فضا آزاد شود."</string>
@@ -464,8 +464,8 @@
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"به برنامه اجازه می‎دهد رایانهٔ لوحی را روشن یا خاموش کند."</string>
     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"به برنامه اجازه می‎دهد گوشی را روشن یا خاموش کند."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"اجرا در حالت تست کارخانه"</string>
-    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"اجرا به عنوان تست سازنده سطح پایین، امکان دسترسی کامل به سخت‌افزار رایانهٔ لوحی شما را فراهم می‌آورد. فقط زمانی که رایانهٔ لوحی در حالت تست سازنده در حال اجراست قابل دسترسی است."</string>
-    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"اجرا به عنوان تست سازنده سطح پایین، امکان دسترسی کامل به سخت‌افزار تلفن شما را فراهم می‌آورد. فقط زمانی که تلفن در حالت تست سازنده در حال اجراست قابل دسترسی است."</string>
+    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"اجرا به‌عنوان تست سازنده سطح پایین، امکان دسترسی کامل به سخت‌افزار رایانهٔ لوحی شما را فراهم می‌آورد. فقط زمانی که رایانهٔ لوحی در حالت تست سازنده در حال اجراست قابل دسترسی است."</string>
+    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"اجرا به‌عنوان تست سازنده سطح پایین، امکان دسترسی کامل به سخت‌افزار تلفن شما را فراهم می‌آورد. فقط زمانی که تلفن در حالت تست سازنده در حال اجراست قابل دسترسی است."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"تنظیم تصویر زمینه"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"به برنامه اجازه می‎دهد تا تصویر زمینه سیستم را تنظیم کند."</string>
     <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"تنظیم اندازه تصویر زمینه"</string>
@@ -478,7 +478,7 @@
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"تنظیم منطقهٔ زمانی"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"به برنامه اجازه می‎دهد تا منطقهٔ زمانی رایانهٔ لوحی را تغییر دهد."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"به برنامه اجازه می‎دهد تا منطقهٔ زمانی تلفن را تغییر دهد."</string>
-    <string name="permlab_accountManagerService" msgid="4829262349691386986">"عملکرد به عنوان AccountManagerService"</string>
+    <string name="permlab_accountManagerService" msgid="4829262349691386986">"عملکرد به‌عنوان AccountManagerService"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">"به برنامه اجازه می‎دهد با AccountAuthenticators تماس برقرار کند."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"یافتن حساب‌ها در دستگاه"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"به برنامه اجازه می‌دهد به لیست حساب‌های شناخته شده توسط رایانهٔ لوحی دسترسی پیدا کند. این ممکن است حسا‌ب‌های ایجاد شده توسط برنامه‌هایی را که نصب کرده‌اید، شامل شود."</string>
@@ -502,7 +502,7 @@
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"تغییر تنظیمات میزان استفاده داده در پس‌زمینه"</string>
     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"به برنامه اجازه می‎دهد تا تنظیم کاربرد داده‎های پس‌زمینه را تغییر دهد."</string>
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"مشاهدهٔ اتصالات Wi-Fi"</string>
-    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"به برنامه امکان می‌دهد اطلاعات مربوط به شبکه Wi-Fi را مشاهده کند، به عنوان مثال فعال بودن Wi-Fi و نام دستگاه‌های Wi-Fi متصل."</string>
+    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"به برنامه امکان می‌دهد اطلاعات مربوط به شبکه Wi-Fi را مشاهده کند، به‌عنوان مثال فعال بودن Wi-Fi و نام دستگاه‌های Wi-Fi متصل."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"اتصال به Wi-Fi و قطع اتصال از آن"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"به برنامه اجازه می‎دهد تا به نقاط دسترسی Wi-Fi وصل شود و ارتباط خود را با آن‌ها قطع کند و تغییراتی را در پیکربندی دستگاه برای شبکه‎های Wi-Fi ایجاد کند."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"دریافت چندگانه Wi-Fi را مجاز می‌کند"</string>
@@ -522,12 +522,12 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"کنترل ارتباط راه نزدیک"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"به برنامه اجازه می‎دهد تا با تگهای ارتباط میدان نزدیک (NFC)، کارتها و فایل خوان ارتباط برقرار کند."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"غیرفعال کردن قفل صفحه شما"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"به برنامه امکان می‌دهد قفل کلید و هر گونه امنیت گذرواژه مرتبط را غیرفعال کند. به عنوان مثال تلفن هنگام دریافت یک تماس تلفنی ورودی قفل کلید را غیرفعال می‌کند و بعد از پایان تماس، قفل کلید را دوباره فعال می‌کند."</string>
-    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگام سازی"</string>
-    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"به برنامه اجازه می‌دهد تنظیمات را برای یک حساب بخواند. به عنوان مثال، این ویژگی می‌تواند تعیین کند آیا حساب «افراد» شما با یک حساب همگام‌سازی شده است."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"به برنامه امکان می‌دهد قفل کلید و هر گونه امنیت گذرواژه مرتبط را غیرفعال کند. به‌عنوان مثال تلفن هنگام دریافت یک تماس تلفنی ورودی قفل کلید را غیرفعال می‌کند و بعد از پایان تماس، قفل کلید را دوباره فعال می‌کند."</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگام‌سازی"</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"به برنامه اجازه می‌دهد تنظیمات را برای یک حساب بخواند. به‌عنوان مثال، این ویژگی می‌تواند تعیین کند آیا حساب «افراد» شما با یک حساب همگام‌سازی شده است."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"تغییر وضعیت همگام‌سازی بین فعال و غیرفعال"</string>
-    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"به یک برنامه اجازه می‌دهد تنظیمات همگام‌سازی را برای یک حساب اصلاح کند. به عنوان مثال، از این ویژگی می‌توان برای فعال کردن همگام‌سازی برنامه «افراد» با یک حساب استفاده کرد."</string>
-    <string name="permlab_readSyncStats" msgid="7396577451360202448">"خواندن اطلاعات آماری همگام سازی"</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"به یک برنامه اجازه می‌دهد تنظیمات همگام‌سازی را برای یک حساب اصلاح کند. به‌عنوان مثال، از این ویژگی می‌توان برای فعال کردن همگام‌سازی برنامه «افراد» با یک حساب استفاده کرد."</string>
+    <string name="permlab_readSyncStats" msgid="7396577451360202448">"خواندن اطلاعات آماری همگام‌سازی"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"به یک برنامه اجازه می‌دهد وضعیت همگام‌سازی یک حساب را بخواند، از جمله سابقه رویدادهای همگام‌سازی و میزان داده‌های همگام‌سازی شده."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"خواندن فیدهای مشترک"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"به برنامه اجازه می‎دهد تا جزئیات مربوط به فیدهای همگام شده کنونی را دریافت کند."</string>
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"به برنامه اجازه می‎دهد تا در کارت SD بنویسد."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تغییر/حذف محتواهای حافظه رسانه داخلی"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"به برنامه اجازه می‎دهد تا محتویات حافظه رسانه داخلی را تغییر دهد."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"دسترسی به سیستم فایل حافظهٔ پنهان"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"به برنامه اجازه می‎دهد تا سیستم فایل حافظهٔ پنهان را بخواند و بنویسد."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"علامتگذاری/دریافت تماس‌های اینترنتی"</string>
@@ -1089,9 +1093,9 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"در صورت فعال کردن حافظهٔ USB، برخی از برنامه‎هایی که از آن‌ها استفاده می‎کنید متوقف می‎شوند و تا زمانی که حافظهٔ USB را غیرفعال نکنید امکان استفاده از آن‌ها وجود نخواهد داشت."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"راه‌اندازی USB ناموفق بود."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به عنوان دستگاه رسانه‌ای"</string>
-    <string name="usb_ptp_notification_title" msgid="1960817192216064833">"متصل شده به عنوان دوربین"</string>
-    <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"متصل شده به عنوان نصب کننده"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به‌عنوان دستگاه رسانه‌ای"</string>
+    <string name="usb_ptp_notification_title" msgid="1960817192216064833">"متصل شده به‌عنوان دوربین"</string>
+    <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"متصل شده به‌عنوان نصب کننده"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"به یک وسیله جانبی USB وصل شده است"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"برای سایر گزینه‌های USB لمس کنید."</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"حافظهٔ USB فرمت شود؟"</string>
@@ -1159,7 +1163,7 @@
     <string name="permission_request_notification_title" msgid="6486759795926237907">"مجوز درخواست شد"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"مجوز"\n"برای حساب <xliff:g id="ACCOUNT">%s</xliff:g> درخواست شد."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"روش ورودی"</string>
-    <string name="sync_binding_label" msgid="3687969138375092423">"همگام سازی"</string>
+    <string name="sync_binding_label" msgid="3687969138375092423">"همگام‌سازی"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"قابلیت دسترسی"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
     <string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"به <xliff:g id="SESSION">%s</xliff:g> وصل شد. برای مدیریت شبکه لمس کنید."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"در حال اتصال VPN همیشه فعال…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN همیشه فعال متصل شد"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطای VPN همیشه فعال"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"برای بازنشانی اتصال لمس کنید"</string>
     <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
     <string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ce355ca..b9d6c06 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Antaa sovelluksen kirjoittaa SD-kortille."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"muokkaa/poista sisäisen säilytystilan sisältöä"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Antaa sovelluksen muokata sisäisen tallennustilan sisältöä."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"käytä välimuistin tiedostojärjestelmää"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Antaa sovelluksen lukea välimuistin tiedostojärjestelmää ja kirjoittaa siihen."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"soita/vastaanota internetpuheluita"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa koskettamalla."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Nollaa yhteys koskettamalla"</string>
     <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
     <string name="reset" msgid="2448168080964209908">"Palauta"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f9250ce..e5f7978 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet à l\'application de modifier le contenu de la carte SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Modifier/Supprimer contenu mémoire interne"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet à l\'application de modifier le contenu de la mémoire de stockage multimédia interne."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accéder au système de fichiers en cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant le système de fichiers du cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"effectuer/recevoir des appels Internet"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index faca09d..fcb0783 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"एप्लिकेशन को SD कार्ड पर लिखने देता है."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"आंतरिक मीडिया संग्रहण सामग्रियों को बदलें/हटाएं"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"एप्लिकेशन को आंतरिक मीडिया संग्रहण की सामग्री को संशोधित करने देता है."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"कैश फ़ाइल सिस्‍टम में पहंचे"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्‍लिकेशन को संचय फ़ाइल सिस्‍टम पढ़ने और लिखने देता है."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"इंटरनेट कॉल करें/प्राप्त करें"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
     <string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g> से कनेक्‍ट किया गया. नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"कनेक्शन रीसेट करने के लिए स्पर्श करें"</string>
     <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
     <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 928761e..01e6557 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"izmijeni/izbriši sadržaj pohranjen na internim medijima"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Aplikaciji omogućuje izmjenu sadržaja pohranjenog na internim medijima."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristup sustavu datoteka predmemorije"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Aplikaciji omogućuje čitanje i pisanje u datotečnom sustavu privremene memorije."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"zovi/primaj internetske pozive"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite za upravljanje mrežom."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dodirnite za poništavanje veze"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index fce9c5b..a48129d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lehetővé teszi az alkalmazás számára, hogy írjon az SD-kártyára."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"belső tár tartalmának módosítása/törlése"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a belső háttértár tartalmát."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"hozzáférés a gyorsítótár fájlrendszeréhez"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Lehetővé teszi az alkalmazás számára a gyorsítótár-fájlrendszer olvasását és írását."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"internetes hívások kezdeményezése és fogadása"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Érintse meg a kapcsolat alaphelyzetbe állításához."</string>
     <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
     <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0c1ff65..77333cd 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Memungkinkan apl menulis ke kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubah/hapus konten penyimpanan media internal"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Mengizinkan apl memodifikasi konten penyimpanan media internal."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem file cache."</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Mengizinkan apl membaca dan menulis pada sistem file cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"lakukan//terima panggilan internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Sentuh untuk mengelola jaringan."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Sentuh untuk menyetel ulang sambungan"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 432f2e4..9f1ee1c 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Consente all\'applicazione di scrivere sulla scheda SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modifica/eliminaz. contenuti archivio media int."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Consente all\'applicazione di modificare i contenuti dell\'archivio media interno."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesso al filesystem nella cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Consente all\'applicazione di leggere e scrivere il filesystem nella cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"effettuazione/ricezione chiamate Internet"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ff17945..d7ce2e1 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"מאפשר ליישום לכתוב לכרטיס ה-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"שנה/מחק תוכן של אחסון מדיה פנימי"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"מאפשר ליישום לשנות את התוכן של אמצעי האחסון הפנימי למדיה."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"גישה למערכת הקבצים בקובץ השמור"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"מאפשר ליישום לקרוא ולכתוב במערכת הקבצים של הקבצים השמורים."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"בצע/קבל שיחות אינטרנט"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 1b2be12..0e1b9eb 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"SDカードへの書き込みをアプリに許可します。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"内部メディアストレージの内容の変更/削除"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"内部メディアストレージの内容を変更することをアプリに許可します。"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"キャッシュファイルシステムにアクセス"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"キャッシュファイルシステムの読み書きをアプリに許可します。"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"インターネット通話の発着信"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5549489..ae9b0c0 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"앱이 SD 카드에 쓸 수 있도록 허용합니다."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"내부 미디어 저장소 콘텐츠 수정/삭제"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"앱이 내부 미디어 저장소의 콘텐츠를 수정할 수 있도록 허용합니다."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"캐시 파일시스템 액세스"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"앱이 캐시 파일 시스템을 읽고 쓸 수 있도록 허용합니다."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"인터넷 전화 걸기/받기"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
     <string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 터치하세요."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"연결 유지 VPN에 연결하는 중…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"연결 유지 VPN에 연결됨"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"터치하여 연결 재설정"</string>
     <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
     <string name="reset" msgid="2448168080964209908">"초기화"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 37b2f83..94c5825 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Leidžiama programai rašyti į SD kortelę."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"keisti / ištr. vid. med. atm. tur."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Leidžiama programai keisti vidinės medijos saugyklos turinį."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pasiekti talpyklos failų sistemą"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Leidžiama programai skaityti talpyklos failų sistemą ir į ją rašyti."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"skambinti / priimti skambučius internetu"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Palieskite, kad iš naujo nustatytumėte ryšį"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
     <string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 38f8047..91b414b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ļauj lietotnei rakstīt SD kartē."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"pārv./dz.datu n.iekš.atm.sat."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ļauj lietotnei modificēt datu nesēja iekšējās atmiņas saturu."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"piekļūt kešatmiņas failu sistēmai"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ļauj lietotnei lasīt un rakstīt kešatmiņas failu sistēmā."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"veikt/saņemt interneta zvanus"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Ir izveidots savienojums ar <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Pieskarieties, lai atiestatītu savienojumu."</string>
     <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
     <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a56f6cf..b9fca83 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Membenarkan apl menulis ke kad SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubh suai/pdm kdg strn mdia dlm"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Membenarkan apl mengubah suai kandungan storan media dalaman."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem fail cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Membenarkan apl membaca dan menulis cache sistem fail."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"membuat/menerima panggilan Internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Bersambung ke <xliff:g id="SESSION">%s</xliff:g>. Sentuh untuk mengurus rangkaian."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Sentuh untuk menetapkan semula sambungan"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a18e63c..ef6a305 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lar appen skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"endre eller slette innhold på interne medier"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lar appen endre innholdet i det interne lagringsmediet."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"tilgang til bufrede filer"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Lar appen lese og skrive til det bufrede filsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"foreta/motta Internett-anrop"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3ac4f86..2ac476d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"inh. mediaopsl. wijz./verw."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Hiermee kan de app de inhoud van de interne mediaopslag aanpassen."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"het cachebestandssysteem openen"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Hiermee kan de app het cachebestandssysteem lezen en schrijven."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"internetoproepen starten/ontvangen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b3cb4f8..bdea11f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pozwala aplikacji na zapis na karcie SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyfikowanie/usuwanie zawartości pamięci wew."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pozwala aplikacji na modyfikowanie zawartości pamięci wewnętrznej."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostęp do systemu plików pamięci podręcznej"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Pozwala aplikacji na odczyt i zapis w systemie plików pamięci podręcznej."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"nawiązywanie/odbieranie połączeń przez internet"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index aab8ca9c..390faaa 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que a aplicação escreva no cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./elim. armaz. interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que a aplicação modifique o conteúdo de armazenamento de suportes internos."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"aceder ao sistema de ficheiros da cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite à aplicação ler e escrever no sistema de ficheiros da cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fazer/receber chamadas pela internet"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 575630f..5ec23f9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que o aplicativo grave em seu cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/excluir conteúdos de armazenamento de mídia internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que o aplicativo modifique o conteúdo da mídia de armazenamento interno."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acessar o sistema de arquivos de cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que o aplicativo leia e grave o sistema de arquivos cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fazer/receber chamadas pela internet"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index eafb3b4..40fad47 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -891,6 +891,10 @@
     <skip />
     <!-- no translation found for permdesc_mediaStorageWrite (8189160597698529185) -->
     <skip />
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"access al sistem da datotecas da cache"</string>
     <!-- no translation found for permdesc_cache_filesystem (5578967642265550955) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 969d3a1..52c0c42 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicaţiei să scrie pe cardul SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./şterg. conţinutul media stocat intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite aplicaţiei să modifice conţinutul stocării media interne."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesare sistem de fişiere cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite aplicaţiei să scrie şi să citească sistemul de fişiere cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"efectuare/primire apeluri prin internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeţi pentru a gestiona reţeaua."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la reţeaua VPN activată permanent…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la reţeaua VPN activată permanent"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de reţea VPN activată permanent"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Atingeţi pentru a reseta conexiunea"</string>
     <string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fişiere"</string>
     <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a7df6c1..a9a0d0c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Приложение сможет записывать данные на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"изм./удал. данных мультимедиа"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Приложение сможет изменять контент внутреннего хранилища мультимедиа."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"получать доступ к кэшу файловой системы"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Приложение сможет выполнять чтение и запись в файловую систему кэша."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Осуществление/прием интернет-вызовов"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Сеть VPN подключена: <xliff:g id="SESSION">%s</xliff:g>. Нажмите, чтобы открыть настройки."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Нажмите, чтобы сбросить соединение"</string>
     <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Сбросить"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 28bfa5e..2bfa219 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikácii zápis na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"úprava alebo odstránenie obsahu interného ukladacieho priestoru média"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikácii zmeniť obsah interného ukladacieho priestoru média."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristupovať do súborového systému vyrovnávacej pamäte"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Umožňuje aplikácii čítať a zapisovať do súborového systému vyrovnávacej pamäte."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"uskutočňovať a prijímať internetové hovory"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po dotyku môžete sieť spravovať."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prebieha pripájanie k vždy zapnutej sieti VPN..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dotykom obnovíte pripojenie"</string>
     <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
     <string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5a9f299..78c2806 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Programu omogoča pisanje na kartico SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"spreminjanje/brisanje vsebine notranje shrambe nosilca podatkov"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Programu omogoča spreminjanje vsebine notranje shrambe nosilca podatkov."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostop do datotečnega sistema predpomnilnika"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Programu omogoča branje in pisanje v datotečni sistem predpomnilnika."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"opravljanje/sprejemanje internetnih klicev"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Vzpostavljena povezava s sejo <xliff:g id="SESSION">%s</xliff:g>. Dotaknite se, če želite upravljati omrežje."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno vklopljeno navidezno zasebno omrežje povezano"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dotaknite se, da ponastavite povezavo"</string>
     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
     <string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index eeeeb30..e7c11b6 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозвољава апликацији да уписује податке на SD картицу."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"измена/брисање интерне меморије медија"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозвољава апликацији да мења садржај интерне меморије медијума."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"приступ систему датотека кеша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дозвољава апликацији да чита систем датотека кеша и уписује податке у њега."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"упућивање/пријем Интернет позива"</string>
@@ -1167,14 +1171,10 @@
     <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_long" msgid="6407351006249174473">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Повезивање стално укљученог VPN-а..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Стално укључени VPN је повезан"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Додирните да бисте ресетовали везу"</string>
     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
     <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 761b8df3..b1009e2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillåter att appen skriver till SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ändra/ta bort innehåll"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillåter att appen ändrar innehållet på den interna lagringsenheten."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"åtkomst till cachefilsystemet"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Tillåter att appen läser och skriver till cachefilsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"ringa/ta emot Internetsamtal"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index dcd2d81..cf489c2 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Inaruhusu programu kuandikia kadi ya SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"badilisha/futa maudhui ya hifadhi ya media ya ndani."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Inaruhusu programu kurekebisha maudhui ya hifadhi ya ndani vyombo vya habari."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"fikia faili za mfumo za kache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Inaruhusu programu kusoma na kuandika mfumo wa faili wa kache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"piga/pokea simu za mtandao"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b9ebf43..9358870 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"อนุญาตให้แอปพลิเคชันเขียนลงบนการ์ด SD"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"แก้/ลบเนื้อหาข้อมูลสื่อภายใน"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"อนุญาตให้แอปพลิเคชันแก้ไขเนื้อหาของที่เก็บข้อมูลสื่อภายใน"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"เข้าถึงระบบไฟล์แคช"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"อนุญาตให้แอปพลิเคชันอ่านและเขียนระบบไฟล์แคช"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"โทรออก/รับสายอินเทอร์เน็ต"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"กำลังเชื่อมต่อ VPN แบบเปิดตลอดเวลา…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"เชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"แตะเพื่อรีเซ็ตการเชื่อมต่อ"</string>
     <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
     <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4f222b7..1147059 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pinapayagan ang app na magsulat sa SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"baguhin/tanggalin ang mga nilalaman ng panloob na imbakan ng media"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pinapayagan ang app na baguhin ang mga nilalaman ng panloob na media storage."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"i-access ang cache filesystem"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Pinapayagan ang app na basahin at isulat ang cache filesystem."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"gumawa/tumanggap ng mga tawag sa Internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Pindutin upang pamahalaan ang network."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Pindutin upang i-reset ang koneksyon"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
     <string name="reset" msgid="2448168080964209908">"I-reset"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index fe80c3e..a4e7d4d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -547,6 +547,10 @@
     <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>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Uygulamaya, dahili medya depolama içeriğini değiştirme izni verir."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"önbellek dosya sistemine eriş"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Uygulamaya, önbellek dosya sisteminde okuma ve yazma yapma izni verir."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"İnternet çağrılar yap/alma"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlandı. Ağı yönetmek için dokunun."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Bağlantıyı sıfırlamak için dokunun"</string>
     <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
     <string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 730c384..5c4a1b1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозволяє програмі записувати на карту SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змінювати/видаляти вміст внутр. сховища даних"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозволяє програмі змінювати вміст внутрішнього сховища даних."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"отр. дост. до файл. сист. кешу"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дозволяє програмі читати з файлової системи кеш-пам’яті та писати в неї."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"здійсн./отрим. Інтернет-дзвін."</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Під’єднано до сеансу <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Під’єднання до постійної мережі VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Під’єднано до постійної мережі VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Торкніться, щоб скинути з’єднання"</string>
     <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
     <string name="reset" msgid="2448168080964209908">"Віднов."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 6ffc84e..66d0f31 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Cho phép ứng dụng ghi vào thẻ SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sửa đổi/xóa nội dung trên bộ nhớ phương tiện cục bộ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Cho phép ứng dụng sửa đổi nội dung của bộ lưu trữ phương tiện nội bộ."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"truy cập hệ thống tệp bộ nhớ cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Cho phép ứng dụng đọc và ghi hệ thống tệp bộ nhớ cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"thực hiện/nhận cuộc gọi qua Internet"</string>
@@ -1167,14 +1171,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Chạm để đặt lại kết nối"</string>
     <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
     <string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 12de741..4c42e4a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允许应用写入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/删除内部媒体存储设备的内容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允许应用修改内部媒体存储设备的内容。"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"访问缓存文件系统"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允许应用读取和写入缓存文件系统。"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网通话"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 84725cf..53f3d39 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允許應用程式寫入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/刪除內部媒體儲存裝置內容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允許應用程式修改內部媒體儲存空間的內容。"</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"存取快取檔案系統"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允許應用程式讀取及寫入快取檔案系統。"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"撥打/接聽網路電話"</string>
@@ -1167,14 +1171,10 @@
     <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_long" msgid="6407351006249174473">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕觸即可管理網路。"</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"輕觸即可重設連線"</string>
     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
     <string name="reset" msgid="2448168080964209908">"重設"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e8eaaa6..232c933 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -547,6 +547,10 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela insiza ukuthi ibhalele ekhadini le-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"guqula/susa okuqukethwe kwisitoreji semidiya yangaphakathi"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela insiza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
+    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
+    <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"finyelela kunqolobane yesistimu yefayela"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela insiza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"yena/thola amakholi e-Inthanethi"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3757afc..9601ad4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2374,6 +2374,12 @@
         <!-- The extra value of the subtype. This string can be any string and will be passed to
              the IME when the framework calls the IME with the subtype.  -->
         <attr name="imeSubtypeExtraValue" format="string" />
+        <!-- The unique id for the subtype. The input method framework keeps track of enabled
+             subtypes by ID. When the IME package gets upgraded, enabled IDs will stay enabled even
+             if other attributes are different. If the ID is unspecified (by calling the other
+             constructor or 0. Arrays.hashCode(new Object[] {locale, mode, extraValue,
+             isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead. -->
+        <attr name="subtypeId" format="integer"/>
     </declare-styleable>
 
     <!-- Use <code>spell-checker</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1c3318d..3a69937 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -639,6 +639,8 @@
              physical screen size has changed such as switching to an external
              display. -->
         <flag name="smallestScreenSize" value="0x0800" />
+        <!-- The layout direction has changed. For example going from LTR to RTL. -->
+        <flag name="layoutDirection" value="0x2000" />
         <!-- The font scaling factor has changed, that is the user has
              selected a new global font size. -->
         <flag name="fontScale" value="0x40000000" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 86d03ad..096ff21 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -471,6 +471,9 @@
          Also, the battery stats are flushed to disk when we hit this level.  -->
     <integer name="config_criticalBatteryWarningLevel">4</integer>
 
+    <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. -->
+    <integer name="config_shutdownBatteryTemperature">680</integer>
+
     <!-- Display low battery warning when battery level dips to this value -->
     <!-- Display low battery warning when battery level dips to this value -->
     <integer name="config_lowBatteryWarningLevel">15</integer>
@@ -479,7 +482,7 @@
     <integer name="config_lowBatteryCloseWarningLevel">20</integer>
 
     <!-- Default color for notification LED. -->
-    <color name="config_defaultNotificationColor">#ff00ff00</color>
+    <color name="config_defaultNotificationColor">#ffffffff</color>
 
     <!-- Default LED on time for notification LED in milliseconds. -->
     <integer name="config_defaultNotificationLedOn">500</integer>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8e0eb15..0f39cc6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -710,6 +710,7 @@
   <java-symbol type="string" name="policydesc_setGlobalProxy" />
   <java-symbol type="string" name="policydesc_watchLogin" />
   <java-symbol type="string" name="policydesc_wipeData" />
+  <java-symbol type="string" name="policydesc_disableKeyguardWidgets" />
   <java-symbol type="string" name="policylab_disableCamera" />
   <java-symbol type="string" name="policylab_encryptedStorage" />
   <java-symbol type="string" name="policylab_expirePassword" />
@@ -719,6 +720,7 @@
   <java-symbol type="string" name="policylab_setGlobalProxy" />
   <java-symbol type="string" name="policylab_watchLogin" />
   <java-symbol type="string" name="policylab_wipeData" />
+  <java-symbol type="string" name="policylab_disableKeyguardWidgets" />
   <java-symbol type="string" name="postalTypeCustom" />
   <java-symbol type="string" name="postalTypeHome" />
   <java-symbol type="string" name="postalTypeOther" />
@@ -1293,7 +1295,7 @@
   <java-symbol type="id" name="passwordEntry" />
   <java-symbol type="id" name="pinDel" />
   <java-symbol type="id" name="pinDisplay" />
-  <java-symbol type="id" name="propertyOf" />
+  <java-symbol type="id" name="owner_info" />
   <java-symbol type="id" name="pukDel" />
   <java-symbol type="id" name="pukDisplay" />
   <java-symbol type="id" name="right_icon" />
@@ -1544,6 +1546,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
+  <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
@@ -3761,5 +3764,6 @@
   <public type="attr" name="listPreferredItemPaddingEnd" />
   <public type="attr" name="singleUser" />
   <public type="attr" name="presentationTheme" />
+  <public type="attr" name="subtypeId"/>
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 381055f..d2951bf 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1693,6 +1693,10 @@
     <string name="policylab_disableCamera">Disable cameras</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
     <string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
+    <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
+    <string name="policylab_disableKeyguardWidgets">Disable widgets on keyguard</string>
+    <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
+    <string name="policydesc_disableKeyguardWidgets">Prevent use of some or all widgets on keyguard.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
diff --git a/docs/html/training/basics/activity-lifecycle/recreating.jd b/docs/html/training/basics/activity-lifecycle/recreating.jd
index 3bbf0bb..8c7126a 100644
--- a/docs/html/training/basics/activity-lifecycle/recreating.jd
+++ b/docs/html/training/basics/activity-lifecycle/recreating.jd
@@ -51,7 +51,7 @@
 the foreground activity because the screen configuration has changed and your activity might need to
 load alternative resources (such as the layout).</p>
 
-<p>By default, the system uses the {@link android.os.Bundle} instance state to saves information
+<p>By default, the system uses the {@link android.os.Bundle} instance state to save information
 about each {@link android.view.View} object in your activity layout (such as the text value entered
 into an {@link android.widget.EditText} object). So, if your activity instance is destroyed and
 recreated, the state of the layout is automatically restored to its previous state. However, your
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 23bca3e..48f5bf3 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -957,6 +957,13 @@
         SCREENLONG_ANY = ACONFIGURATION_SCREENLONG_ANY << SHIFT_SCREENLONG,
         SCREENLONG_NO = ACONFIGURATION_SCREENLONG_NO << SHIFT_SCREENLONG,
         SCREENLONG_YES = ACONFIGURATION_SCREENLONG_YES << SHIFT_SCREENLONG,
+
+        // screenLayout bits for layout direction.
+        MASK_LAYOUTDIR = 0xC0,
+        SHIFT_LAYOUTDIR = 6,
+        LAYOUTDIR_ANY = ACONFIGURATION_LAYOUTDIR_ANY << SHIFT_LAYOUTDIR,
+        LAYOUTDIR_LTR = ACONFIGURATION_LAYOUTDIR_LTR << SHIFT_LAYOUTDIR,
+        LAYOUTDIR_RTL = ACONFIGURATION_LAYOUTDIR_RTL << SHIFT_LAYOUTDIR,
     };
     
     enum {
@@ -1020,7 +1027,8 @@
         CONFIG_SMALLEST_SCREEN_SIZE = ACONFIGURATION_SMALLEST_SCREEN_SIZE,
         CONFIG_VERSION = ACONFIGURATION_VERSION,
         CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
-        CONFIG_UI_MODE = ACONFIGURATION_UI_MODE
+        CONFIG_UI_MODE = ACONFIGURATION_UI_MODE,
+        CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR,
     };
     
     // Compare two configuration, returning CONFIG_* flags set for each value
@@ -1061,7 +1069,7 @@
  * There should be one of these chunks for each resource type.
  *
  * This structure is followed by an array of integers providing the set of
- * configuation change flags (ResTable_config::CONFIG_*) that have multiple
+ * configuration change flags (ResTable_config::CONFIG_*) that have multiple
  * resources for that configuration.  In addition, the high bit is set if that
  * resource has been made public.
  */
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 8cce191..069dfa3 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1470,6 +1470,9 @@
     if (country[1] != o.country[1]) {
         return country[1] < o.country[1] ? -1 : 1;
     }
+    if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) {
+        return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1;
+    }
     if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
         return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
     }
@@ -1558,6 +1561,13 @@
         }
     }
 
+    if (screenLayout || o.screenLayout) {
+        if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) {
+            if (!(screenLayout & MASK_LAYOUTDIR)) return false;
+            if (!(o.screenLayout & MASK_LAYOUTDIR)) return true;
+        }
+    }
+
     if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
         if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
             if (!smallestScreenWidthDp) return false;
@@ -1683,6 +1693,15 @@
             }
         }
 
+        if (screenLayout || o.screenLayout) {
+            if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
+                    && (requested->screenLayout & MASK_LAYOUTDIR)) {
+                int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
+                int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
+                return (myLayoutDir > oLayoutDir);
+            }
+        }
+
         if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
             // The configuration closest to the actual size is best.
             // We assume that larger configs have already been filtered
@@ -1906,6 +1925,12 @@
         }
     }
     if (screenConfig != 0) {
+        const int layoutDir = screenLayout&MASK_LAYOUTDIR;
+        const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
+        if (layoutDir != 0 && layoutDir != setLayoutDir) {
+            return false;
+        }
+
         const int screenSize = screenLayout&MASK_SCREENSIZE;
         const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
         // Any screen sizes for larger screens than the setting do not
@@ -2032,6 +2057,21 @@
         if (res.size() > 0) res.append("-");
         res.append(country, 2);
     }
+    if ((screenLayout&MASK_LAYOUTDIR) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
+            case ResTable_config::LAYOUTDIR_LTR:
+                res.append("ltr");
+                break;
+            case ResTable_config::LAYOUTDIR_RTL:
+                res.append("rtl");
+                break;
+            default:
+                res.appendFormat("layoutDir=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR));
+                break;
+        }
+    }
     if (smallestScreenWidthDp != 0) {
         if (res.size() > 0) res.append("-");
         res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index c3a07a1..c0f79df 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -6,6 +6,8 @@
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES:= \
 		utils/SortedListImpl.cpp \
+		font/CacheTexture.cpp \
+		font/Font.cpp \
 		FontRenderer.cpp \
 		GammaFontRenderer.cpp \
 		Caches.cpp \
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 95ccdfc..86667ee 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -25,585 +25,12 @@
 #include "Caches.h"
 #include "Debug.h"
 #include "FontRenderer.h"
-#include "Caches.h"
+#include "Rect.h"
 
 namespace android {
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024
-#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 256
-#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
-#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
-#define CACHE_BLOCK_ROUNDING_SIZE 4
-
-#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
-
-///////////////////////////////////////////////////////////////////////////////
-// CacheBlock
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
- * order, except for the final block (the remainder space at the right, since we fill from the
- * left).
- */
-CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock *newBlock) {
-#if DEBUG_FONT_RENDERER
-    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
-            newBlock, newBlock->mX, newBlock->mY,
-            newBlock->mWidth, newBlock->mHeight);
-#endif
-    CacheBlock *currBlock = head;
-    CacheBlock *prevBlock = NULL;
-    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
-        if (newBlock->mWidth < currBlock->mWidth) {
-            newBlock->mNext = currBlock;
-            newBlock->mPrev = prevBlock;
-            currBlock->mPrev = newBlock;
-            if (prevBlock) {
-                prevBlock->mNext = newBlock;
-                return head;
-            } else {
-                return newBlock;
-            }
-        }
-        prevBlock = currBlock;
-        currBlock = currBlock->mNext;
-    }
-    // new block larger than all others - insert at end (but before the remainder space, if there)
-    newBlock->mNext = currBlock;
-    newBlock->mPrev = prevBlock;
-    if (currBlock) {
-        currBlock->mPrev = newBlock;
-    }
-    if (prevBlock) {
-        prevBlock->mNext = newBlock;
-        return head;
-    } else {
-        return newBlock;
-    }
-}
-
-CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove) {
-#if DEBUG_FONT_RENDERER
-    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
-            blockToRemove, blockToRemove->mX, blockToRemove->mY,
-            blockToRemove->mWidth, blockToRemove->mHeight);
-#endif
-    CacheBlock* newHead = head;
-    CacheBlock* nextBlock = blockToRemove->mNext;
-    CacheBlock* prevBlock = blockToRemove->mPrev;
-    if (prevBlock) {
-        prevBlock->mNext = nextBlock;
-    } else {
-        newHead = nextBlock;
-    }
-    if (nextBlock) {
-        nextBlock->mPrev = prevBlock;
-    }
-    delete blockToRemove;
-    return newHead;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CacheTexture
-///////////////////////////////////////////////////////////////////////////////
-
-bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
-    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) {
-        return false;
-    }
-
-    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
-    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
-    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
-    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
-    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
-    // of varying sizes in one block.
-    uint16_t roundedUpW =
-            (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
-    CacheBlock *cacheBlock = mCacheBlocks;
-    while (cacheBlock) {
-        // Store glyph in this block iff: it fits the block's remaining space and:
-        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
-        // or it's within ROUNDING_SIZE of the block width
-        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
-                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
-                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
-            if (cacheBlock->mHeight - glyphH < glyphH) {
-                // Only enough space for this glyph - don't bother rounding up the width
-                roundedUpW = glyphW;
-            }
-            *retOriginX = cacheBlock->mX;
-            *retOriginY = cacheBlock->mY;
-            // If this is the remainder space, create a new cache block for this column. Otherwise,
-            // adjust the info about this column.
-            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
-                uint16_t oldX = cacheBlock->mX;
-                // Adjust remainder space dimensions
-                cacheBlock->mWidth -= roundedUpW;
-                cacheBlock->mX += roundedUpW;
-                if (mHeight - glyphH >= glyphH) {
-                    // There's enough height left over to create a new CacheBlock
-                    CacheBlock *newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
-                            roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE);
-#if DEBUG_FONT_RENDERER
-                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
-                            newBlock, newBlock->mX, newBlock->mY,
-                            newBlock->mWidth, newBlock->mHeight);
-#endif
-                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
-                }
-            } else {
-                // Insert into current column and adjust column dimensions
-                cacheBlock->mY += glyphH;
-                cacheBlock->mHeight -= glyphH;
-#if DEBUG_FONT_RENDERER
-                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
-                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
-                        cacheBlock->mWidth, cacheBlock->mHeight);
-#endif
-            }
-            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
-                // If remaining space in this block is too small to be useful, remove it
-                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
-            }
-            mDirty = true;
-#if DEBUG_FONT_RENDERER
-            ALOGD("fitBitmap: current block list:");
-            mCacheBlocks->output();
-#endif
-            ++mNumGlyphs;
-            return true;
-        }
-        cacheBlock = cacheBlock->mNext;
-    }
-#if DEBUG_FONT_RENDERER
-    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
-#endif
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Font
-///////////////////////////////////////////////////////////////////////////////
-
-Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
-        int flags, uint32_t italicStyle, uint32_t scaleX,
-        SkPaint::Style style, uint32_t strokeWidth) :
-        mState(state), mFontId(fontId), mFontSize(fontSize),
-        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
-        mStyle(style), mStrokeWidth(mStrokeWidth) {
-}
-
-
-Font::~Font() {
-    for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
-        if (mState->mActiveFonts[ct] == this) {
-            mState->mActiveFonts.removeAt(ct);
-            break;
-        }
-    }
-
-    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
-        delete mCachedGlyphs.valueAt(i);
-    }
-}
-
-void Font::invalidateTextureCache(CacheTexture *cacheTexture) {
-    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
-        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
-        if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) {
-            cachedGlyph->mIsValid = false;
-        }
-    }
-}
-
-void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
-        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
-    int nPenX = x + glyph->mBitmapLeft;
-    int nPenY = y + glyph->mBitmapTop;
-
-    int width = (int) glyph->mBitmapWidth;
-    int height = (int) glyph->mBitmapHeight;
-
-    if (bounds->bottom > nPenY) {
-        bounds->bottom = nPenY;
-    }
-    if (bounds->left > nPenX) {
-        bounds->left = nPenX;
-    }
-    if (bounds->right < nPenX + width) {
-        bounds->right = nPenX + width;
-    }
-    if (bounds->top < nPenY + height) {
-        bounds->top = nPenY + height;
-    }
-}
-
-void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
-        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
-    int nPenX = x + glyph->mBitmapLeft;
-    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
-
-    float u1 = glyph->mBitmapMinU;
-    float u2 = glyph->mBitmapMaxU;
-    float v1 = glyph->mBitmapMinV;
-    float v2 = glyph->mBitmapMaxV;
-
-    int width = (int) glyph->mBitmapWidth;
-    int height = (int) glyph->mBitmapHeight;
-
-    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
-            nPenX + width, nPenY, u2, v2,
-            nPenX + width, nPenY - height, u2, v1,
-            nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
-}
-
-void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
-        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
-    int nPenX = x + glyph->mBitmapLeft;
-    int nPenY = y + glyph->mBitmapTop;
-
-    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
-    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
-
-    CacheTexture *cacheTexture = glyph->mCacheTexture;
-    uint32_t cacheWidth = cacheTexture->mWidth;
-    const uint8_t* cacheBuffer = cacheTexture->mTexture;
-
-    uint32_t cacheX = 0, cacheY = 0;
-    int32_t bX = 0, bY = 0;
-    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
-        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
-#if DEBUG_FONT_RENDERER
-            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
-                ALOGE("Skipping invalid index");
-                continue;
-            }
-#endif
-            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
-            bitmap[bY * bitmapW + bX] = tempCol;
-        }
-    }
-}
-
-void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
-        SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
-    const float halfWidth = glyph->mBitmapWidth * 0.5f;
-    const float height = glyph->mBitmapHeight;
-
-    vOffset += glyph->mBitmapTop + height;
-
-    SkPoint destination[4];
-    measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
-
-    // Move along the tangent and offset by the normal
-    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
-            -tangent->fY * halfWidth + tangent->fX * vOffset);
-    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
-            tangent->fY * halfWidth + tangent->fX * vOffset);
-    destination[2].set(destination[1].fX + tangent->fY * height,
-            destination[1].fY - tangent->fX * height);
-    destination[3].set(destination[0].fX + tangent->fY * height,
-            destination[0].fY - tangent->fX * height);
-
-    const float u1 = glyph->mBitmapMinU;
-    const float u2 = glyph->mBitmapMaxU;
-    const float v1 = glyph->mBitmapMinV;
-    const float v2 = glyph->mBitmapMaxV;
-
-    mState->appendRotatedMeshQuad(
-            position->fX + destination[0].fX,
-            position->fY + destination[0].fY, u1, v2,
-            position->fX + destination[1].fX,
-            position->fY + destination[1].fY, u2, v2,
-            position->fX + destination[2].fX,
-            position->fY + destination[2].fY, u2, v1,
-            position->fX + destination[3].fX,
-            position->fY + destination[3].fY, u1, v1,
-            glyph->mCacheTexture);
-}
-
-CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
-    CachedGlyphInfo* cachedGlyph = NULL;
-    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
-    if (index >= 0) {
-        cachedGlyph = mCachedGlyphs.valueAt(index);
-    } else {
-        cachedGlyph = cacheGlyph(paint, textUnit, precaching);
-    }
-
-    // Is the glyph still in texture cache?
-    if (!cachedGlyph->mIsValid) {
-        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
-        updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
-    }
-
-    return cachedGlyph;
-}
-
-void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
-        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
-    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
-        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
-                bitmapW, bitmapH, NULL, NULL);
-    } else {
-        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
-                0, 0, NULL, NULL);
-    }
-}
-
-void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, int x, int y, const float* positions) {
-    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
-            0, 0, NULL, positions);
-}
-
-void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
-    if (numGlyphs == 0 || text == NULL || len == 0) {
-        return;
-    }
-
-    text += start;
-
-    int glyphsCount = 0;
-    SkFixed prevRsbDelta = 0;
-
-    float penX = 0.0f;
-
-    SkPoint position;
-    SkVector tangent;
-
-    SkPathMeasure measure(*path, false);
-    float pathLength = SkScalarToFloat(measure.getLength());
-
-    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
-        float textWidth = SkScalarToFloat(paint->measureText(text, len));
-        float pathOffset = pathLength;
-        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
-            textWidth *= 0.5f;
-            pathOffset *= 0.5f;
-        }
-        penX += pathOffset - textWidth;
-    }
-
-    while (glyphsCount < numGlyphs && penX < pathLength) {
-        glyph_t glyph = GET_GLYPH(text);
-
-        if (IS_END_OF_STRING(glyph)) {
-            break;
-        }
-
-        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
-        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
-        prevRsbDelta = cachedGlyph->mRsbDelta;
-
-        if (cachedGlyph->mIsValid) {
-            drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
-        }
-
-        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
-
-        glyphsCount++;
-    }
-}
-
-void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
-        int numGlyphs, Rect *bounds, const float* positions) {
-    if (bounds == NULL) {
-        ALOGE("No return rectangle provided to measure text");
-        return;
-    }
-    bounds->set(1e6, -1e6, -1e6, 1e6);
-    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
-}
-
-void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
-
-    if (numGlyphs == 0 || text == NULL) {
-        return;
-    }
-    int glyphsCount = 0;
-
-    while (glyphsCount < numGlyphs) {
-        glyph_t glyph = GET_GLYPH(text);
-
-        // Reached the end of the string
-        if (IS_END_OF_STRING(glyph)) {
-            break;
-        }
-
-        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
-
-        glyphsCount++;
-    }
-}
-
-void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
-        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
-        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
-    if (numGlyphs == 0 || text == NULL || len == 0) {
-        return;
-    }
-
-    static RenderGlyph gRenderGlyph[] = {
-            &android::uirenderer::Font::drawCachedGlyph,
-            &android::uirenderer::Font::drawCachedGlyphBitmap,
-            &android::uirenderer::Font::measureCachedGlyph
-    };
-    RenderGlyph render = gRenderGlyph[mode];
-
-    text += start;
-    int glyphsCount = 0;
-
-    if (CC_LIKELY(positions == NULL)) {
-        SkFixed prevRsbDelta = 0;
-
-        float penX = x + 0.5f;
-        int penY = y;
-
-        while (glyphsCount < numGlyphs) {
-            glyph_t glyph = GET_GLYPH(text);
-
-            // Reached the end of the string
-            if (IS_END_OF_STRING(glyph)) {
-                break;
-            }
-
-            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
-            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
-            prevRsbDelta = cachedGlyph->mRsbDelta;
-
-            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
-            if (cachedGlyph->mIsValid) {
-                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
-                        bitmap, bitmapW, bitmapH, bounds, positions);
-            }
-
-            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
-
-            glyphsCount++;
-        }
-    } else {
-        const SkPaint::Align align = paint->getTextAlign();
-
-        // This is for renderPosText()
-        while (glyphsCount < numGlyphs) {
-            glyph_t glyph = GET_GLYPH(text);
-
-            // Reached the end of the string
-            if (IS_END_OF_STRING(glyph)) {
-                break;
-            }
-
-            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
-
-            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
-            if (cachedGlyph->mIsValid) {
-                int penX = x + positions[(glyphsCount << 1)];
-                int penY = y + positions[(glyphsCount << 1) + 1];
-
-                switch (align) {
-                    case SkPaint::kRight_Align:
-                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
-                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
-                        break;
-                    case SkPaint::kCenter_Align:
-                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
-                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
-                    default:
-                        break;
-                }
-
-                (*this.*render)(cachedGlyph, penX, penY,
-                        bitmap, bitmapW, bitmapH, bounds, positions);
-            }
-
-            glyphsCount++;
-        }
-    }
-}
-
-void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
-        bool precaching) {
-    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
-    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
-    glyph->mBitmapLeft = skiaGlyph.fLeft;
-    glyph->mBitmapTop = skiaGlyph.fTop;
-    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
-    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
-
-    uint32_t startX = 0;
-    uint32_t startY = 0;
-
-    // Get the bitmap for the glyph
-    paint->findImage(skiaGlyph);
-    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
-
-    if (!glyph->mIsValid) {
-        return;
-    }
-
-    uint32_t endX = startX + skiaGlyph.fWidth;
-    uint32_t endY = startY + skiaGlyph.fHeight;
-
-    glyph->mStartX = startX;
-    glyph->mStartY = startY;
-    glyph->mBitmapWidth = skiaGlyph.fWidth;
-    glyph->mBitmapHeight = skiaGlyph.fHeight;
-
-    uint32_t cacheWidth = glyph->mCacheTexture->mWidth;
-    uint32_t cacheHeight = glyph->mCacheTexture->mHeight;
-
-    glyph->mBitmapMinU = startX / (float) cacheWidth;
-    glyph->mBitmapMinV = startY / (float) cacheHeight;
-    glyph->mBitmapMaxU = endX / (float) cacheWidth;
-    glyph->mBitmapMaxV = endY / (float) cacheHeight;
-
-    mState->mUploadTexture = true;
-}
-
-CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) {
-    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
-    mCachedGlyphs.add(glyph, newGlyph);
-
-    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
-    newGlyph->mGlyphIndex = skiaGlyph.fID;
-    newGlyph->mIsValid = false;
-
-    updateGlyphCache(paint, skiaGlyph, newGlyph, precaching);
-
-    return newGlyph;
-}
-
-Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
-        int flags, uint32_t italicStyle, uint32_t scaleX,
-        SkPaint::Style style, uint32_t strokeWidth) {
-    Vector<Font*> &activeFonts = state->mActiveFonts;
-
-    for (uint32_t i = 0; i < activeFonts.size(); i++) {
-        Font* font = activeFonts[i];
-        if (font->mFontId == fontId && font->mFontSize == fontSize &&
-                font->mFlags == flags && font->mItalicStyle == italicStyle &&
-                font->mScaleX == scaleX && font->mStyle == style &&
-                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
-            return font;
-        }
-    }
-
-    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
-            scaleX, style, strokeWidth);
-    activeFonts.push(newFont);
-    return newFont;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -619,7 +46,7 @@
     mMaxNumberOfQuads = 1024;
     mCurrentQuadIndex = 0;
 
-    mTextMeshPtr = NULL;
+    mTextMesh = NULL;
     mCurrentCacheTexture = NULL;
     mLastCacheTexture = NULL;
 
@@ -636,20 +63,25 @@
     if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
         mSmallCacheWidth = atoi(property);
     }
+
     if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
         mSmallCacheHeight = atoi(property);
     }
+
     if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
         mLargeCacheWidth = atoi(property);
     }
+
     if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
         mLargeCacheHeight = atoi(property);
     }
-    GLint maxTextureSize = Caches::getInstance().maxTextureSize;
-    mSmallCacheWidth = (mSmallCacheWidth > maxTextureSize) ? maxTextureSize : mSmallCacheWidth;
-    mSmallCacheHeight = (mSmallCacheHeight > maxTextureSize) ? maxTextureSize : mSmallCacheHeight;
-    mLargeCacheWidth = (mLargeCacheWidth > maxTextureSize) ? maxTextureSize : mLargeCacheWidth;
-    mLargeCacheHeight = (mLargeCacheHeight > maxTextureSize) ? maxTextureSize : mLargeCacheHeight;
+
+    uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
+    mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
+    mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
+    mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
+    mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
+
     if (sLogFontRendererCreate) {
         INIT_LOGD("  Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
                 mSmallCacheWidth, mSmallCacheHeight,
@@ -672,7 +104,7 @@
         Caches::getInstance().unbindIndicesBuffer();
         glDeleteBuffers(1, &mIndexBufferID);
 
-        delete[] mTextMeshPtr;
+        delete[] mTextMesh;
     }
 
     Vector<Font*> fontsToDereference = mActiveFonts;
@@ -695,68 +127,34 @@
         mCacheTextures[i]->init();
     }
 
-    #if DEBUG_FONT_RENDERER
+#if DEBUG_FONT_RENDERER
     uint16_t totalGlyphs = 0;
     for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        totalGlyphs += mCacheTextures[i]->mNumGlyphs;
+        totalGlyphs += mCacheTextures[i]->getGlyphCount();
         // Erase caches, just as a debugging facility
-        if (mCacheTextures[i]->mTexture) {
-            memset(mCacheTextures[i]->mTexture, 0,
-                    mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight);
+        if (mCacheTextures[i]->getTexture()) {
+            memset(mCacheTextures[i]->getTexture(), 0,
+                    mCacheTextures[i]->getWidth() * mCacheTextures[i]->getHeight());
         }
     }
     ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
 #endif
 }
 
-void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
-    if (cacheTexture && cacheTexture->mTexture) {
-        glDeleteTextures(1, &cacheTexture->mTextureId);
-        delete[] cacheTexture->mTexture;
-        cacheTexture->mTexture = NULL;
-        cacheTexture->mTextureId = 0;
-    }
-}
-
 void FontRenderer::flushLargeCaches() {
     // Start from 1; don't deallocate smallest/default texture
     for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
         CacheTexture* cacheTexture = mCacheTextures[i];
-        if (cacheTexture->mTexture != NULL) {
+        if (cacheTexture->getTexture()) {
             cacheTexture->init();
             for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
                 mActiveFonts[j]->invalidateTextureCache(cacheTexture);
             }
-            deallocateTextureMemory(cacheTexture);
+            cacheTexture->releaseTexture();
         }
     }
 }
 
-void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
-    int width = cacheTexture->mWidth;
-    int height = cacheTexture->mHeight;
-
-    cacheTexture->mTexture = new uint8_t[width * height];
-
-    if (!cacheTexture->mTextureId) {
-        glGenTextures(1, &cacheTexture->mTextureId);
-    }
-
-    Caches::getInstance().activeTexture(0);
-    glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    // Initialize texture dimensions
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
-            GL_ALPHA, GL_UNSIGNED_BYTE, 0);
-
-    const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST;
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
-
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
 CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
         uint32_t* startX, uint32_t* startY) {
     for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
@@ -774,7 +172,7 @@
     cachedGlyph->mIsValid = false;
     // If the glyph is too tall, don't cache it
     if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
-                mCacheTextures[mCacheTextures.size() - 1]->mHeight) {
+                mCacheTextures[mCacheTextures.size() - 1]->getHeight()) {
         ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                 (int) glyph.fWidth, (int) glyph.fHeight);
         return;
@@ -808,14 +206,15 @@
     uint32_t endX = startX + glyph.fWidth;
     uint32_t endY = startY + glyph.fHeight;
 
-    uint32_t cacheWidth = cacheTexture->mWidth;
+    uint32_t cacheWidth = cacheTexture->getWidth();
 
-    if (!cacheTexture->mTexture) {
+    if (!cacheTexture->getTexture()) {
+        Caches::getInstance().activeTexture(0);
         // Large-glyph texture memory is allocated only as needed
-        allocateTextureMemory(cacheTexture);
+        cacheTexture->allocateTexture();
     }
 
-    uint8_t* cacheBuffer = cacheTexture->mTexture;
+    uint8_t* cacheBuffer = cacheTexture->getTexture();
     uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
     unsigned int stride = glyph.rowBytes();
 
@@ -855,7 +254,8 @@
     CacheTexture* cacheTexture = new CacheTexture(width, height);
 
     if (allocate) {
-        allocateTextureMemory(cacheTexture);
+        Caches::getInstance().activeTexture(0);
+        cacheTexture->allocateTexture();
     }
 
     return cacheTexture;
@@ -905,7 +305,7 @@
     uint32_t uvSize = 2;
     uint32_t vertsPerQuad = 4;
     uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
-    mTextMeshPtr = new float[vertexBufferSize];
+    mTextMesh = new float[vertexBufferSize];
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -930,16 +330,16 @@
     // Iterate over all the cache textures and see which ones need to be updated
     for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
         CacheTexture* cacheTexture = mCacheTextures[i];
-        if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) {
+        if (cacheTexture->isDirty() && cacheTexture->getTexture()) {
             uint32_t xOffset = 0;
-            uint32_t width   = cacheTexture->mWidth;
-            uint32_t height  = cacheTexture->mHeight;
-            void* textureData = cacheTexture->mTexture;
+            uint32_t width = cacheTexture->getWidth();
+            uint32_t height = cacheTexture->getHeight();
+            void* textureData = cacheTexture->getTexture();
 
-            if (cacheTexture->mTextureId != lastTextureId) {
+            if (cacheTexture->getTextureId() != lastTextureId) {
+                lastTextureId = cacheTexture->getTextureId();
                 caches.activeTexture(0);
-                glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
-                lastTextureId = cacheTexture->mTextureId;
+                glBindTexture(GL_TEXTURE_2D, lastTextureId);
             }
 #if DEBUG_FONT_RENDERER
             ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d",
@@ -948,18 +348,14 @@
             glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height,
                     GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
 
-            cacheTexture->mDirty = false;
+            cacheTexture->setDirty(false);
         }
     }
 
     caches.activeTexture(0);
-    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
-    if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) {
-        const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST;
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
-        mCurrentCacheTexture->mLinearFiltering = mLinearFiltering;
-    }
+    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->getTextureId());
+
+    mCurrentCacheTexture->setLinearFiltering(mLinearFiltering, false);
     mLastCacheTexture = mCurrentCacheTexture;
 
     mUploadTexture = false;
@@ -971,7 +367,7 @@
     Caches& caches = Caches::getInstance();
     caches.bindIndicesBuffer(mIndexBufferID);
     if (!mDrawn) {
-        float* buffer = mTextMeshPtr;
+        float* buffer = mTextMesh;
         int offset = 2;
 
         bool force = caches.unbindMeshBuffer();
@@ -1000,7 +396,7 @@
 
     const uint32_t vertsPerQuad = 4;
     const uint32_t floatsPerVert = 4;
-    float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
+    float* currentPos = mTextMesh + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
 
     (*currentPos++) = x1;
     (*currentPos++) = y1;
@@ -1213,6 +609,19 @@
     return mDrawn;
 }
 
+void FontRenderer::removeFont(const Font* font) {
+    for (uint32_t ct = 0; ct < mActiveFonts.size(); ct++) {
+        if (mActiveFonts[ct] == font) {
+            mActiveFonts.removeAt(ct);
+            break;
+        }
+    }
+
+    if (mCurrentFont == font) {
+        mCurrentFont = NULL;
+    }
+}
+
 void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
     // Compute gaussian weights for the blur
     // e is the euler's number
@@ -1300,7 +709,6 @@
     float currentPixel = 0.0f;
 
     for (int32_t y = 0; y < height; y ++) {
-
         uint8_t* output = dest + y * width;
 
         for (int32_t x = 0; x < width; x ++) {
@@ -1334,7 +742,7 @@
                 }
             }
             *output = (uint8_t) blurredPixel;
-            output ++;
+            output++;
         }
     }
 }
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 241b73e..405db09 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,268 +17,22 @@
 #ifndef ANDROID_HWUI_FONT_RENDERER_H
 #define ANDROID_HWUI_FONT_RENDERER_H
 
-#include <utils/String8.h>
-#include <utils/String16.h>
 #include <utils/Vector.h>
-#include <utils/KeyedVector.h>
 
-#include <SkScalerContext.h>
 #include <SkPaint.h>
-#include <SkPathMeasure.h>
-#include <SkPoint.h>
 
 #include <GLES2/gl2.h>
 
-#include "Rect.h"
+#include "font/FontUtil.h"
+#include "font/CacheTexture.h"
+#include "font/CachedGlyphInfo.h"
+#include "font/Font.h"
 #include "Properties.h"
 
 namespace android {
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-#if RENDER_TEXT_AS_GLYPHS
-    typedef uint16_t glyph_t;
-    #define TO_GLYPH(g) g
-    #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
-    #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
-    #define IS_END_OF_STRING(glyph) false
-#else
-    typedef SkUnichar glyph_t;
-    #define TO_GLYPH(g) ((SkUnichar) g)
-    #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
-    #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
-    #define IS_END_OF_STRING(glyph) glyph < 0
-#endif
-
-#define TEXTURE_BORDER_SIZE 1
-
-///////////////////////////////////////////////////////////////////////////////
-// Declarations
-///////////////////////////////////////////////////////////////////////////////
-
-class FontRenderer;
-
-/**
- * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
- * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
- * When we add a glyph to the cache, we see if it fits within one of the existing columns that
- * have already been started (this is the case if the glyph fits vertically as well as
- * horizontally, and if its width is sufficiently close to the column width to avoid
- * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
- * glyph fits, we check the final node, which is the remaining space in the cache, creating
- * a new column as appropriate.
- *
- * As columns fill up, we remove their CacheBlock from the list to avoid having to check
- * small blocks in the future.
- */
-struct CacheBlock {
-    uint16_t mX;
-    uint16_t mY;
-    uint16_t mWidth;
-    uint16_t mHeight;
-    CacheBlock* mNext;
-    CacheBlock* mPrev;
-
-    CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false):
-        mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL)
-    {
-    }
-
-    static CacheBlock* insertBlock(CacheBlock* head, CacheBlock *newBlock);
-
-    static CacheBlock* removeBlock(CacheBlock* head, CacheBlock *blockToRemove);
-
-    void output() {
-        CacheBlock *currBlock = this;
-        while (currBlock) {
-            ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
-                    currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight);
-            currBlock = currBlock->mNext;
-        }
-    }
-};
-
-class CacheTexture {
-public:
-    CacheTexture(uint16_t width, uint16_t height) :
-            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
-            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
-        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
-                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
-    }
-
-    ~CacheTexture() {
-        if (mTexture) {
-            delete[] mTexture;
-        }
-        if (mTextureId) {
-            glDeleteTextures(1, &mTextureId);
-        }
-        reset();
-    }
-
-    void reset() {
-        // Delete existing cache blocks
-        while (mCacheBlocks != NULL) {
-            CacheBlock* tmpBlock = mCacheBlocks;
-            mCacheBlocks = mCacheBlocks->mNext;
-            delete tmpBlock;
-        }
-        mNumGlyphs = 0;
-    }
-
-    void init() {
-        // reset, then create a new remainder space to start again
-        reset();
-        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
-                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
-    }
-
-    bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
-
-    uint8_t* mTexture;
-    GLuint mTextureId;
-    uint16_t mWidth;
-    uint16_t mHeight;
-    bool mLinearFiltering;
-    bool mDirty;
-    uint16_t mNumGlyphs;
-    CacheBlock* mCacheBlocks;
-};
-
-struct CachedGlyphInfo {
-    // Has the cache been invalidated?
-    bool mIsValid;
-    // Location of the cached glyph in the bitmap
-    // in case we need to resize the texture or
-    // render to bitmap
-    uint32_t mStartX;
-    uint32_t mStartY;
-    uint32_t mBitmapWidth;
-    uint32_t mBitmapHeight;
-    // Also cache texture coords for the quad
-    float mBitmapMinU;
-    float mBitmapMinV;
-    float mBitmapMaxU;
-    float mBitmapMaxV;
-    // Minimize how much we call freetype
-    uint32_t mGlyphIndex;
-    uint32_t mAdvanceX;
-    uint32_t mAdvanceY;
-    // Values below contain a glyph's origin in the bitmap
-    int32_t mBitmapLeft;
-    int32_t mBitmapTop;
-    // Auto-kerning
-    SkFixed mLsbDelta;
-    SkFixed mRsbDelta;
-    CacheTexture* mCacheTexture;
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Font
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Represents a font, defined by a Skia font id and a font size. A font is used
- * to generate glyphs and cache them in the FontState.
- */
-class Font {
-public:
-    enum Style {
-        kFakeBold = 1
-    };
-
-    ~Font();
-
-    /**
-     * Renders the specified string of text.
-     * If bitmap is specified, it will be used as the render target
-     */
-    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, int x, int y, uint8_t *bitmap = NULL,
-            uint32_t bitmapW = 0, uint32_t bitmapH = 0);
-
-    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, int x, int y, const float* positions);
-
-    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, SkPath* path, float hOffset, float vOffset);
-
-    /**
-     * Creates a new font associated with the specified font state.
-     */
-    static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
-            int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
-            uint32_t strokeWidth);
-
-protected:
-    friend class FontRenderer;
-    typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
-            uint32_t, uint32_t, Rect*, const float*);
-
-    enum RenderMode {
-        FRAMEBUFFER,
-        BITMAP,
-        MEASURE,
-    };
-
-    void precache(SkPaint* paint, const char* text, int numGlyphs);
-
-    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
-            uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions);
-
-    void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
-            int numGlyphs, Rect *bounds, const float* positions);
-
-    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
-            uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
-
-    // Cache of glyphs
-    DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
-
-    void invalidateTextureCache(CacheTexture *cacheTexture = NULL);
-
-    CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching);
-    void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
-            bool precaching);
-
-    void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
-            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
-            Rect* bounds, const float* pos);
-    void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
-            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
-            Rect* bounds, const float* pos);
-    void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
-            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
-            Rect* bounds, const float* pos);
-    void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
-            SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
-
-    CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false);
-
-    static glyph_t nextGlyph(const uint16_t** srcPtr) {
-        const uint16_t* src = *srcPtr;
-        glyph_t g = *src++;
-        *srcPtr = src;
-        return g;
-    }
-
-    FontRenderer* mState;
-    uint32_t mFontId;
-    float mFontSize;
-    int mFlags;
-    uint32_t mItalicStyle;
-    uint32_t mScaleX;
-    SkPaint::Style mStyle;
-    uint32_t mStrokeWidth;
-};
-
-///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -331,31 +85,24 @@
     GLuint getTexture(bool linearFiltering = false) {
         checkInit();
 
-        if (linearFiltering != mCurrentCacheTexture->mLinearFiltering) {
-            mCurrentCacheTexture->mLinearFiltering = linearFiltering;
-            mLinearFiltering = linearFiltering;
-            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
+        mCurrentCacheTexture->setLinearFiltering(linearFiltering);
+        mLinearFiltering = linearFiltering;
 
-            glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
-        }
-
-        return mCurrentCacheTexture->mTextureId;
+        return mCurrentCacheTexture->getTextureId();
     }
 
     uint32_t getCacheSize() const {
         uint32_t size = 0;
         for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
             CacheTexture* cacheTexture = mCacheTextures[i];
-            if (cacheTexture != NULL && cacheTexture->mTexture != NULL) {
-                size += cacheTexture->mWidth * cacheTexture->mHeight;
+            if (cacheTexture && cacheTexture->getTexture()) {
+                size += cacheTexture->getWidth() * cacheTexture->getHeight();
             }
         }
         return size;
     }
 
-protected:
+private:
     friend class Font;
 
     const uint8_t* mGammaTable;
@@ -389,6 +136,14 @@
             float x3, float y3, float u3, float v3,
             float x4, float y4, float u4, float v4, CacheTexture* texture);
 
+    void removeFont(const Font* font);
+
+    void checkTextureUpdate();
+
+    void setTextureDirty() {
+        mUploadTexture = true;
+    }
+
     uint32_t mSmallCacheWidth;
     uint32_t mSmallCacheHeight;
     uint32_t mLargeCacheWidth;
@@ -402,11 +157,10 @@
     CacheTexture* mCurrentCacheTexture;
     CacheTexture* mLastCacheTexture;
 
-    void checkTextureUpdate();
     bool mUploadTexture;
 
     // Pointer to vertex data to speed up frame to frame work
-    float *mTextMeshPtr;
+    float* mTextMesh;
     uint32_t mCurrentQuadIndex;
     uint32_t mMaxNumberOfQuads;
 
@@ -420,12 +174,13 @@
 
     bool mLinearFiltering;
 
-    void computeGaussianWeights(float* weights, int32_t radius);
-    void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
+    /** We should consider multi-threading this code or using Renderscript **/
+    static void computeGaussianWeights(float* weights, int32_t radius);
+    static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
             int32_t width, int32_t height);
-    void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
+    static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
             int32_t width, int32_t height);
-    void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius);
+    static void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius);
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2f43be8..7abcc63 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1933,7 +1933,7 @@
         // This value is used in the fragment shader to determine how to fill fragments.
         // We will need to calculate the actual width proportion on each segment for
         // scaled non-hairlines, since the boundary proportion may differ per-axis when scaled.
-        float boundaryWidthProportion = 1 / (2 * halfStrokeWidth);
+        float boundaryWidthProportion = .5 - 1 / (2 * halfStrokeWidth);
         setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
                 boundaryWidthProportion, widthSlot, lengthSlot);
     }
@@ -1997,9 +1997,9 @@
                 abVector.x *= inverseScaleX;
                 abVector.y *= inverseScaleY;
                 float abLength = abVector.length();
-                boundaryLengthProportion = abLength / (length + abLength);
+                boundaryLengthProportion = .5 - abLength / (length + abLength);
             } else {
-                boundaryLengthProportion = .5 / (length + 1);
+                boundaryLengthProportion = .5 - .5 / (length + 1);
             }
 
             abVector /= 2;
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
new file mode 100644
index 0000000..4a3af12
--- /dev/null
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#include <utils/Log.h>
+
+#include "Debug.h"
+#include "CacheTexture.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// CacheBlock
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
+ * order, except for the final block (the remainder space at the right, since we fill from the
+ * left).
+ */
+CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
+#if DEBUG_FONT_RENDERER
+    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
+            newBlock, newBlock->mX, newBlock->mY,
+            newBlock->mWidth, newBlock->mHeight);
+#endif
+
+    CacheBlock* currBlock = head;
+    CacheBlock* prevBlock = NULL;
+
+    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
+        if (newBlock->mWidth < currBlock->mWidth) {
+            newBlock->mNext = currBlock;
+            newBlock->mPrev = prevBlock;
+            currBlock->mPrev = newBlock;
+
+            if (prevBlock) {
+                prevBlock->mNext = newBlock;
+                return head;
+            } else {
+                return newBlock;
+            }
+        }
+
+        prevBlock = currBlock;
+        currBlock = currBlock->mNext;
+    }
+
+    // new block larger than all others - insert at end (but before the remainder space, if there)
+    newBlock->mNext = currBlock;
+    newBlock->mPrev = prevBlock;
+
+    if (currBlock) {
+        currBlock->mPrev = newBlock;
+    }
+
+    if (prevBlock) {
+        prevBlock->mNext = newBlock;
+        return head;
+    } else {
+        return newBlock;
+    }
+}
+
+CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
+#if DEBUG_FONT_RENDERER
+    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
+            blockToRemove, blockToRemove->mX, blockToRemove->mY,
+            blockToRemove->mWidth, blockToRemove->mHeight);
+#endif
+
+    CacheBlock* newHead = head;
+    CacheBlock* nextBlock = blockToRemove->mNext;
+    CacheBlock* prevBlock = blockToRemove->mPrev;
+
+    if (prevBlock) {
+        prevBlock->mNext = nextBlock;
+    } else {
+        newHead = nextBlock;
+    }
+
+    if (nextBlock) {
+        nextBlock->mPrev = prevBlock;
+    }
+
+    delete blockToRemove;
+
+    return newHead;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CacheTexture
+///////////////////////////////////////////////////////////////////////////////
+
+bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
+    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
+        return false;
+    }
+
+    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
+    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
+
+    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
+    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
+    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
+    // of varying sizes in one block.
+    uint16_t roundedUpW = (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
+
+    CacheBlock* cacheBlock = mCacheBlocks;
+    while (cacheBlock) {
+        // Store glyph in this block iff: it fits the block's remaining space and:
+        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
+        // or it's within ROUNDING_SIZE of the block width
+        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
+                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
+                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
+            if (cacheBlock->mHeight - glyphH < glyphH) {
+                // Only enough space for this glyph - don't bother rounding up the width
+                roundedUpW = glyphW;
+            }
+
+            *retOriginX = cacheBlock->mX;
+            *retOriginY = cacheBlock->mY;
+
+            // If this is the remainder space, create a new cache block for this column. Otherwise,
+            // adjust the info about this column.
+            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
+                uint16_t oldX = cacheBlock->mX;
+                // Adjust remainder space dimensions
+                cacheBlock->mWidth -= roundedUpW;
+                cacheBlock->mX += roundedUpW;
+
+                if (mHeight - glyphH >= glyphH) {
+                    // There's enough height left over to create a new CacheBlock
+                    CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
+                            roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE);
+#if DEBUG_FONT_RENDERER
+                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                            newBlock, newBlock->mX, newBlock->mY,
+                            newBlock->mWidth, newBlock->mHeight);
+#endif
+                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
+                }
+            } else {
+                // Insert into current column and adjust column dimensions
+                cacheBlock->mY += glyphH;
+                cacheBlock->mHeight -= glyphH;
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
+                        cacheBlock->mWidth, cacheBlock->mHeight);
+#endif
+            }
+
+            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
+                // If remaining space in this block is too small to be useful, remove it
+                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
+            }
+
+            mDirty = true;
+            mNumGlyphs++;
+
+#if DEBUG_FONT_RENDERER
+            ALOGD("fitBitmap: current block list:");
+            mCacheBlocks->output();
+#endif
+
+            return true;
+        }
+        cacheBlock = cacheBlock->mNext;
+    }
+#if DEBUG_FONT_RENDERER
+    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
+#endif
+    return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
new file mode 100644
index 0000000..bf1f4a9
--- /dev/null
+++ b/libs/hwui/font/CacheTexture.h
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_CACHE_TEXTURE_H
+#define ANDROID_HWUI_CACHE_TEXTURE_H
+
+#include <GLES2/gl2.h>
+
+#include <SkScalerContext.h>
+
+#include <utils/Log.h>
+
+#include "FontUtil.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
+ * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
+ * When we add a glyph to the cache, we see if it fits within one of the existing columns that
+ * have already been started (this is the case if the glyph fits vertically as well as
+ * horizontally, and if its width is sufficiently close to the column width to avoid
+ * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
+ * glyph fits, we check the final node, which is the remaining space in the cache, creating
+ * a new column as appropriate.
+ *
+ * As columns fill up, we remove their CacheBlock from the list to avoid having to check
+ * small blocks in the future.
+ */
+struct CacheBlock {
+    uint16_t mX;
+    uint16_t mY;
+    uint16_t mWidth;
+    uint16_t mHeight;
+    CacheBlock* mNext;
+    CacheBlock* mPrev;
+
+    CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false):
+            mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
+    }
+
+    static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
+
+    static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
+
+    void output() {
+        CacheBlock* currBlock = this;
+        while (currBlock) {
+            ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                    currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight);
+            currBlock = currBlock->mNext;
+        }
+    }
+};
+
+class CacheTexture {
+public:
+    CacheTexture(uint16_t width, uint16_t height) :
+            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
+            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
+        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+    }
+
+    ~CacheTexture() {
+        if (mTexture) {
+            delete[] mTexture;
+        }
+        if (mTextureId) {
+            glDeleteTextures(1, &mTextureId);
+        }
+        reset();
+    }
+
+    void reset() {
+        // Delete existing cache blocks
+        while (mCacheBlocks != NULL) {
+            CacheBlock* tmpBlock = mCacheBlocks;
+            mCacheBlocks = mCacheBlocks->mNext;
+            delete tmpBlock;
+        }
+        mNumGlyphs = 0;
+    }
+
+    void init() {
+        // reset, then create a new remainder space to start again
+        reset();
+        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+    }
+
+    void releaseTexture() {
+        if (mTexture) {
+            glDeleteTextures(1, &mTextureId);
+            delete[] mTexture;
+            mTexture = NULL;
+            mTextureId = 0;
+        }
+    }
+
+    /**
+     * This method assumes that the proper texture unit is active.
+     */
+    void allocateTexture() {
+        int width = mWidth;
+        int height = mHeight;
+
+        mTexture = new uint8_t[width * height];
+
+        if (!mTextureId) {
+            glGenTextures(1, &mTextureId);
+        }
+
+        glBindTexture(GL_TEXTURE_2D, mTextureId);
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        // Initialize texture dimensions
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
+                GL_ALPHA, GL_UNSIGNED_BYTE, 0);
+
+        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+
+    bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
+
+    inline uint16_t getWidth() const {
+        return mWidth;
+    }
+
+    inline uint16_t getHeight() const {
+        return mHeight;
+    }
+
+    inline uint8_t* getTexture() const {
+        return mTexture;
+    }
+
+    inline GLuint getTextureId() const {
+        return mTextureId;
+    }
+
+    inline bool isDirty() const {
+        return mDirty;
+    }
+
+    inline void setDirty(bool dirty) {
+        mDirty = dirty;
+    }
+
+    inline bool getLinearFiltering() const {
+        return mLinearFiltering;
+    }
+
+    /**
+     * This method assumes that the proper texture unit is active.
+     */
+    void setLinearFiltering(bool linearFiltering, bool bind = true) {
+        if (linearFiltering != mLinearFiltering) {
+            mLinearFiltering = linearFiltering;
+
+            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
+            if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+        }
+    }
+
+    inline uint16_t getGlyphCount() const {
+        return mNumGlyphs;
+    }
+
+private:
+    uint8_t* mTexture;
+    GLuint mTextureId;
+    uint16_t mWidth;
+    uint16_t mHeight;
+    bool mLinearFiltering;
+    bool mDirty;
+    uint16_t mNumGlyphs;
+    CacheBlock* mCacheBlocks;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_CACHE_TEXTURE_H
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
new file mode 100644
index 0000000..6680a00
--- /dev/null
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_CACHED_GLYPH_INFO_H
+#define ANDROID_HWUI_CACHED_GLYPH_INFO_H
+
+#include <SkFixed.h>
+
+#include "CacheTexture.h"
+
+namespace android {
+namespace uirenderer {
+
+struct CachedGlyphInfo {
+    // Has the cache been invalidated?
+    bool mIsValid;
+    // Location of the cached glyph in the bitmap
+    // in case we need to resize the texture or
+    // render to bitmap
+    uint32_t mStartX;
+    uint32_t mStartY;
+    uint32_t mBitmapWidth;
+    uint32_t mBitmapHeight;
+    // Also cache texture coords for the quad
+    float mBitmapMinU;
+    float mBitmapMinV;
+    float mBitmapMaxU;
+    float mBitmapMaxV;
+    // Minimize how much we call freetype
+    uint32_t mGlyphIndex;
+    uint32_t mAdvanceX;
+    uint32_t mAdvanceY;
+    // Values below contain a glyph's origin in the bitmap
+    int32_t mBitmapLeft;
+    int32_t mBitmapTop;
+    // Auto-kerning
+    SkFixed mLsbDelta;
+    SkFixed mRsbDelta;
+    CacheTexture* mCacheTexture;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
new file mode 100644
index 0000000..34e1a68
--- /dev/null
+++ b/libs/hwui/font/Font.cpp
@@ -0,0 +1,441 @@
+/*
+ * 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.
+ */
+
+#include <cutils/compiler.h>
+
+#include <SkUtils.h>
+
+#include "Debug.h"
+#include "FontUtil.h"
+#include "Font.h"
+#include "FontRenderer.h"
+#include "Properties.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Font
+///////////////////////////////////////////////////////////////////////////////
+
+Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
+        int flags, uint32_t italicStyle, uint32_t scaleX,
+        SkPaint::Style style, uint32_t strokeWidth) :
+        mState(state), mFontId(fontId), mFontSize(fontSize),
+        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
+        mStyle(style), mStrokeWidth(mStrokeWidth) {
+}
+
+
+Font::~Font() {
+    mState->removeFont(this);
+
+    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
+        delete mCachedGlyphs.valueAt(i);
+    }
+}
+
+void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
+    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
+        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
+        if (cacheTexture || cachedGlyph->mCacheTexture == cacheTexture) {
+            cachedGlyph->mIsValid = false;
+        }
+    }
+}
+
+void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
+        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+    int nPenX = x + glyph->mBitmapLeft;
+    int nPenY = y + glyph->mBitmapTop;
+
+    int width = (int) glyph->mBitmapWidth;
+    int height = (int) glyph->mBitmapHeight;
+
+    if (bounds->bottom > nPenY) {
+        bounds->bottom = nPenY;
+    }
+    if (bounds->left > nPenX) {
+        bounds->left = nPenX;
+    }
+    if (bounds->right < nPenX + width) {
+        bounds->right = nPenX + width;
+    }
+    if (bounds->top < nPenY + height) {
+        bounds->top = nPenY + height;
+    }
+}
+
+void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
+        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+    int nPenX = x + glyph->mBitmapLeft;
+    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
+
+    float u1 = glyph->mBitmapMinU;
+    float u2 = glyph->mBitmapMaxU;
+    float v1 = glyph->mBitmapMinV;
+    float v2 = glyph->mBitmapMaxV;
+
+    int width = (int) glyph->mBitmapWidth;
+    int height = (int) glyph->mBitmapHeight;
+
+    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
+            nPenX + width, nPenY, u2, v2,
+            nPenX + width, nPenY - height, u2, v1,
+            nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
+}
+
+void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
+        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+    int nPenX = x + glyph->mBitmapLeft;
+    int nPenY = y + glyph->mBitmapTop;
+
+    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
+    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
+
+    CacheTexture* cacheTexture = glyph->mCacheTexture;
+    uint32_t cacheWidth = cacheTexture->getWidth();
+    const uint8_t* cacheBuffer = cacheTexture->getTexture();
+
+    uint32_t cacheX = 0, cacheY = 0;
+    int32_t bX = 0, bY = 0;
+    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
+        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+#if DEBUG_FONT_RENDERER
+            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
+                ALOGE("Skipping invalid index");
+                continue;
+            }
+#endif
+            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
+            bitmap[bY * bitmapW + bX] = tempCol;
+        }
+    }
+}
+
+void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
+        SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
+    const float halfWidth = glyph->mBitmapWidth * 0.5f;
+    const float height = glyph->mBitmapHeight;
+
+    vOffset += glyph->mBitmapTop + height;
+
+    SkPoint destination[4];
+    measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
+
+    // Move along the tangent and offset by the normal
+    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
+            -tangent->fY * halfWidth + tangent->fX * vOffset);
+    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
+            tangent->fY * halfWidth + tangent->fX * vOffset);
+    destination[2].set(destination[1].fX + tangent->fY * height,
+            destination[1].fY - tangent->fX * height);
+    destination[3].set(destination[0].fX + tangent->fY * height,
+            destination[0].fY - tangent->fX * height);
+
+    const float u1 = glyph->mBitmapMinU;
+    const float u2 = glyph->mBitmapMaxU;
+    const float v1 = glyph->mBitmapMinV;
+    const float v2 = glyph->mBitmapMaxV;
+
+    mState->appendRotatedMeshQuad(
+            position->fX + destination[0].fX,
+            position->fY + destination[0].fY, u1, v2,
+            position->fX + destination[1].fX,
+            position->fY + destination[1].fY, u2, v2,
+            position->fX + destination[2].fX,
+            position->fY + destination[2].fY, u2, v1,
+            position->fX + destination[3].fX,
+            position->fY + destination[3].fY, u1, v1,
+            glyph->mCacheTexture);
+}
+
+CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
+    CachedGlyphInfo* cachedGlyph = NULL;
+    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
+    if (index >= 0) {
+        cachedGlyph = mCachedGlyphs.valueAt(index);
+    } else {
+        cachedGlyph = cacheGlyph(paint, textUnit, precaching);
+    }
+
+    // Is the glyph still in texture cache?
+    if (!cachedGlyph->mIsValid) {
+        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
+        updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
+    }
+
+    return cachedGlyph;
+}
+
+void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
+    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
+        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
+                bitmapW, bitmapH, NULL, NULL);
+    } else {
+        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
+                0, 0, NULL, NULL);
+    }
+}
+
+void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+            int numGlyphs, int x, int y, const float* positions) {
+    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
+            0, 0, NULL, positions);
+}
+
+void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
+    if (numGlyphs == 0 || text == NULL || len == 0) {
+        return;
+    }
+
+    text += start;
+
+    int glyphsCount = 0;
+    SkFixed prevRsbDelta = 0;
+
+    float penX = 0.0f;
+
+    SkPoint position;
+    SkVector tangent;
+
+    SkPathMeasure measure(*path, false);
+    float pathLength = SkScalarToFloat(measure.getLength());
+
+    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
+        float textWidth = SkScalarToFloat(paint->measureText(text, len));
+        float pathOffset = pathLength;
+        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
+            textWidth *= 0.5f;
+            pathOffset *= 0.5f;
+        }
+        penX += pathOffset - textWidth;
+    }
+
+    while (glyphsCount < numGlyphs && penX < pathLength) {
+        glyph_t glyph = GET_GLYPH(text);
+
+        if (IS_END_OF_STRING(glyph)) {
+            break;
+        }
+
+        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
+        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
+        prevRsbDelta = cachedGlyph->mRsbDelta;
+
+        if (cachedGlyph->mIsValid) {
+            drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
+        }
+
+        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
+
+        glyphsCount++;
+    }
+}
+
+void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+        int numGlyphs, Rect *bounds, const float* positions) {
+    if (bounds == NULL) {
+        ALOGE("No return rectangle provided to measure text");
+        return;
+    }
+    bounds->set(1e6, -1e6, -1e6, 1e6);
+    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
+}
+
+void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
+
+    if (numGlyphs == 0 || text == NULL) {
+        return;
+    }
+    int glyphsCount = 0;
+
+    while (glyphsCount < numGlyphs) {
+        glyph_t glyph = GET_GLYPH(text);
+
+        // Reached the end of the string
+        if (IS_END_OF_STRING(glyph)) {
+            break;
+        }
+
+        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
+
+        glyphsCount++;
+    }
+}
+
+void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
+        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
+    if (numGlyphs == 0 || text == NULL || len == 0) {
+        return;
+    }
+
+    static RenderGlyph gRenderGlyph[] = {
+            &android::uirenderer::Font::drawCachedGlyph,
+            &android::uirenderer::Font::drawCachedGlyphBitmap,
+            &android::uirenderer::Font::measureCachedGlyph
+    };
+    RenderGlyph render = gRenderGlyph[mode];
+
+    text += start;
+    int glyphsCount = 0;
+
+    if (CC_LIKELY(positions == NULL)) {
+        SkFixed prevRsbDelta = 0;
+
+        float penX = x + 0.5f;
+        int penY = y;
+
+        while (glyphsCount < numGlyphs) {
+            glyph_t glyph = GET_GLYPH(text);
+
+            // Reached the end of the string
+            if (IS_END_OF_STRING(glyph)) {
+                break;
+            }
+
+            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
+            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
+            prevRsbDelta = cachedGlyph->mRsbDelta;
+
+            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
+            if (cachedGlyph->mIsValid) {
+                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
+                        bitmap, bitmapW, bitmapH, bounds, positions);
+            }
+
+            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
+
+            glyphsCount++;
+        }
+    } else {
+        const SkPaint::Align align = paint->getTextAlign();
+
+        // This is for renderPosText()
+        while (glyphsCount < numGlyphs) {
+            glyph_t glyph = GET_GLYPH(text);
+
+            // Reached the end of the string
+            if (IS_END_OF_STRING(glyph)) {
+                break;
+            }
+
+            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
+
+            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
+            if (cachedGlyph->mIsValid) {
+                int penX = x + positions[(glyphsCount << 1)];
+                int penY = y + positions[(glyphsCount << 1) + 1];
+
+                switch (align) {
+                    case SkPaint::kRight_Align:
+                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
+                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
+                        break;
+                    case SkPaint::kCenter_Align:
+                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
+                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
+                    default:
+                        break;
+                }
+
+                (*this.*render)(cachedGlyph, penX, penY,
+                        bitmap, bitmapW, bitmapH, bounds, positions);
+            }
+
+            glyphsCount++;
+        }
+    }
+}
+
+void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
+        bool precaching) {
+    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
+    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
+    glyph->mBitmapLeft = skiaGlyph.fLeft;
+    glyph->mBitmapTop = skiaGlyph.fTop;
+    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
+    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
+
+    uint32_t startX = 0;
+    uint32_t startY = 0;
+
+    // Get the bitmap for the glyph
+    paint->findImage(skiaGlyph);
+    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
+
+    if (!glyph->mIsValid) {
+        return;
+    }
+
+    uint32_t endX = startX + skiaGlyph.fWidth;
+    uint32_t endY = startY + skiaGlyph.fHeight;
+
+    glyph->mStartX = startX;
+    glyph->mStartY = startY;
+    glyph->mBitmapWidth = skiaGlyph.fWidth;
+    glyph->mBitmapHeight = skiaGlyph.fHeight;
+
+    uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
+    uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
+
+    glyph->mBitmapMinU = startX / (float) cacheWidth;
+    glyph->mBitmapMinV = startY / (float) cacheHeight;
+    glyph->mBitmapMaxU = endX / (float) cacheWidth;
+    glyph->mBitmapMaxV = endY / (float) cacheHeight;
+
+    mState->setTextureDirty();
+}
+
+CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) {
+    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
+    mCachedGlyphs.add(glyph, newGlyph);
+
+    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
+    newGlyph->mGlyphIndex = skiaGlyph.fID;
+    newGlyph->mIsValid = false;
+
+    updateGlyphCache(paint, skiaGlyph, newGlyph, precaching);
+
+    return newGlyph;
+}
+
+Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
+        int flags, uint32_t italicStyle, uint32_t scaleX,
+        SkPaint::Style style, uint32_t strokeWidth) {
+    Vector<Font*> &activeFonts = state->mActiveFonts;
+
+    for (uint32_t i = 0; i < activeFonts.size(); i++) {
+        Font* font = activeFonts[i];
+        if (font->mFontId == fontId && font->mFontSize == fontSize &&
+                font->mFlags == flags && font->mItalicStyle == italicStyle &&
+                font->mScaleX == scaleX && font->mStyle == style &&
+                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
+            return font;
+        }
+    }
+
+    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
+            scaleX, style, strokeWidth);
+    activeFonts.push(newFont);
+    return newFont;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
new file mode 100644
index 0000000..7cab31e
--- /dev/null
+++ b/libs/hwui/font/Font.h
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_FONT_H
+#define ANDROID_HWUI_FONT_H
+
+#include <utils/KeyedVector.h>
+
+#include <SkScalerContext.h>
+#include <SkPaint.h>
+#include <SkPathMeasure.h>
+
+#include "CachedGlyphInfo.h"
+#include "../Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Font
+///////////////////////////////////////////////////////////////////////////////
+
+class FontRenderer;
+
+/**
+ * Represents a font, defined by a Skia font id and a font size. A font is used
+ * to generate glyphs and cache them in the FontState.
+ */
+class Font {
+public:
+    enum Style {
+        kFakeBold = 1
+    };
+
+    ~Font();
+
+    /**
+     * Renders the specified string of text.
+     * If bitmap is specified, it will be used as the render target
+     */
+    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+            int numGlyphs, int x, int y, uint8_t *bitmap = NULL,
+            uint32_t bitmapW = 0, uint32_t bitmapH = 0);
+
+    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+            int numGlyphs, int x, int y, const float* positions);
+
+    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+            int numGlyphs, SkPath* path, float hOffset, float vOffset);
+
+    /**
+     * Creates a new font associated with the specified font state.
+     */
+    static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
+            int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
+            uint32_t strokeWidth);
+
+private:
+    friend class FontRenderer;
+    typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
+            uint32_t, uint32_t, Rect*, const float*);
+
+    enum RenderMode {
+        FRAMEBUFFER,
+        BITMAP,
+        MEASURE,
+    };
+
+    void precache(SkPaint* paint, const char* text, int numGlyphs);
+
+    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+            int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
+            uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions);
+
+    void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+            int numGlyphs, Rect *bounds, const float* positions);
+
+    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
+            uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
+
+    // Cache of glyphs
+    DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
+
+    void invalidateTextureCache(CacheTexture* cacheTexture = NULL);
+
+    CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching);
+    void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
+            bool precaching);
+
+    void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
+            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
+            Rect* bounds, const float* pos);
+    void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
+            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
+            Rect* bounds, const float* pos);
+    void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
+            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
+            Rect* bounds, const float* pos);
+    void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
+            SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
+
+    CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false);
+
+    FontRenderer* mState;
+    uint32_t mFontId;
+    float mFontSize;
+    int mFlags;
+    uint32_t mItalicStyle;
+    uint32_t mScaleX;
+    SkPaint::Style mStyle;
+    uint32_t mStrokeWidth;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_FONT_H
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
new file mode 100644
index 0000000..12247ba
--- /dev/null
+++ b/libs/hwui/font/FontUtil.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_FONT_UTIL_H
+#define ANDROID_HWUI_FONT_UTIL_H
+
+#include <SkUtils.h>
+
+#include "Properties.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024
+#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 256
+#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
+#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
+
+#define TEXTURE_BORDER_SIZE 1
+
+#define CACHE_BLOCK_ROUNDING_SIZE 4
+
+#if RENDER_TEXT_AS_GLYPHS
+    typedef uint16_t glyph_t;
+    #define TO_GLYPH(g) g
+    #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
+    #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
+    #define IS_END_OF_STRING(glyph) false
+
+    static glyph_t nextGlyph(const uint16_t** srcPtr) {
+        const uint16_t* src = *srcPtr;
+        glyph_t g = *src++;
+        *srcPtr = src;
+        return g;
+    }
+#else
+    typedef SkUnichar glyph_t;
+    #define TO_GLYPH(g) ((SkUnichar) g)
+    #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
+    #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
+    #define IS_END_OF_STRING(glyph) glyph < 0
+#endif
+
+#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
+
+#endif // ANDROID_HWUI_FONT_UTIL_H
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 7eb51dd..74cf80e 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -123,6 +123,11 @@
     return config->smallestScreenWidthDp;
 }
 
+int32_t AConfiguration_getLayoutDirection(AConfiguration* config) {
+    return (config->screenLayout&ResTable_config::MASK_LAYOUTDIR)
+            >> ResTable_config::SHIFT_LAYOUTDIR;
+}
+
 // ----------------------------------------------------------------------
 
 void AConfiguration_setMcc(AConfiguration* config, int32_t mcc) {
@@ -210,6 +215,11 @@
     config->smallestScreenWidthDp = value;
 }
 
+void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) {
+    config->screenLayout = (config->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+            | ((value<<ResTable_config::SHIFT_LAYOUTDIR)&ResTable_config::MASK_LAYOUTDIR);
+}
+
 // ----------------------------------------------------------------------
 
 int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b185471..7176f32 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -167,7 +167,7 @@
             android:name=".BeanBag"
             android:exported="true"
             android:label="BeanBag"
-            android:icon="@drawable/redbeandroid"
+            android:icon="@drawable/redbean2"
             android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
             android:hardwareAccelerated="true"
             android:launchMode="singleInstance"
@@ -184,7 +184,9 @@
         <service
             android:name=".BeanBagDream"
             android:exported="true"
-            android:label="Beans in space">
+            android:label="@string/jelly_bean_dream_name"
+            android:enabled="false"
+            >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 66d65d9..a55091d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -73,8 +73,8 @@
     <string name="screenshot_failed_title" msgid="705781116746922771">"تصویر صفحه گرفته نشد."</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"تصویر صفحه ذخیره نشد. ممکن است دستگاه ذخیره‌ در حال استفاده باشد."</string>
     <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="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 File Transfer را برای Mac نصب کنید"</string>
     <string name="accessibility_back" msgid="567011538994429120">"برگشت"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"صفحهٔ اصلی"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f820464..59730af 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -58,8 +58,8 @@
     <string name="label_view" msgid="6304565553218192990">"הצג"</string>
     <string name="always_use_device" msgid="1450287437017315906">"השתמש כברירת מחדל עבור מכשיר USB זה"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"השתמש כברירת מחדל עבור אביזר USB זה"</string>
-    <string name="usb_debugging_title" msgid="1114766024068112429">"האם לאפשר ניפוי באגים ב-USB?"</string>
-    <string name="usb_debugging_message" msgid="719863946976291180">"האם להרשות ניפוי באגים ב-USB ממחשב זה?"\n"טביעת האצבע של מפתח ה-RSA שלך היא"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"האם לאפשר ניקוי באגים ב-USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"האם להרשות ניקוי באגים ב-USB ממחשב זה?"\n"טביעת האצבע של מפתח ה-RSA שלך היא"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="4253099426793114693">"הרשה תמיד במחשב זה"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"הגדל תצוגה כדי למלא את המסך"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index de63d9f..bf01a8d 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -29,5 +29,8 @@
     <!-- Whether recents thumbnails should stretch in both x and y to fill their
      ImageView -->
     <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool>
+
+    <!-- Min alpha % that recent items will fade to while being dismissed -->
+    <integer name="config_recent_item_min_alpha">0</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 13622e6..34e58a3 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -78,5 +78,8 @@
     <integer name="navigation_bar_deadzone_decay">333</integer>
     
     <bool name="config_dead_zone_flash">false</bool>
+
+    <!-- Min alpha % that recent items will fade to while being dismissed -->
+    <integer name="config_recent_item_min_alpha">3</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5747f22..609d63b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -397,4 +397,7 @@
 
     <!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
     <string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
+
+    <!-- Name of the Jelly Bean platlogo screensaver -->
+    <string name="jelly_bean_dream_name">BeanFlinger</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBag.java b/packages/SystemUI/src/com/android/systemui/BeanBag.java
index 616d72f..f5a90ca 100644
--- a/packages/SystemUI/src/com/android/systemui/BeanBag.java
+++ b/packages/SystemUI/src/com/android/systemui/BeanBag.java
@@ -24,6 +24,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.Bitmap;
@@ -40,6 +41,7 @@
 import android.graphics.RectF;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Pair;
@@ -402,6 +404,11 @@
     public void onStart() {
         super.onStart();
 
+        // ACHIEVEMENT UNLOCKED
+        PackageManager pm = getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(this, BeanBagDream.class),
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
         getWindow().addFlags(
                   WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 2512c02..0671e44 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -30,10 +30,8 @@
 import android.renderscript.Matrix4f;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
-import android.view.Display;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
-import android.view.WindowManager;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 2a225d9..6d84350 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -30,7 +30,6 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
-import android.os.UserHandle;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -254,10 +253,9 @@
     public boolean onTouch(View v, MotionEvent ev) {
         int action = ev.getAction() & MotionEvent.ACTION_MASK;
         if (action == MotionEvent.ACTION_DOWN) {
-            mHandler.post(mPreloadTasksRunnable);
+            preloadRecentTasksList();
         } else if (action == MotionEvent.ACTION_CANCEL) {
-            cancelLoadingThumbnailsAndIcons();
-            mHandler.removeCallbacks(mPreloadTasksRunnable);
+            cancelPreloadingRecentTasksList();
         } else if (action == MotionEvent.ACTION_UP) {
             // Remove the preloader if we haven't called it yet
             mHandler.removeCallbacks(mPreloadTasksRunnable);
@@ -269,6 +267,15 @@
         return false;
     }
 
+    public void preloadRecentTasksList() {
+        mHandler.post(mPreloadTasksRunnable);
+    }
+
+    public void cancelPreloadingRecentTasksList() {
+        cancelLoadingThumbnailsAndIcons();
+        mHandler.removeCallbacks(mPreloadTasksRunnable);
+    }
+
     public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
         // Only oblige this request if it comes from the current RecentsPanel
         // (eg when you rotate, the old RecentsPanel request should be ignored)
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index a4c8e64..baacde01 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -136,6 +136,8 @@
         mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
         mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
         recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
+        mRecentsPanel.setMinSwipeAlpha(
+                getResources().getInteger(R.integer.config_recent_item_min_alpha) / 100f);
 
         handleIntent(getIntent());
         mIntentFilter = new IntentFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index c3ecdb5..730d350 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -38,15 +38,11 @@
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Display;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.AdapterView;
@@ -60,7 +56,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 import com.android.systemui.statusbar.tablet.TabletStatusBar;
@@ -72,7 +67,6 @@
     static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
     private Context mContext;
-    private BaseStatusBar mBar;
     private PopupMenu mPopup;
     private View mRecentsScrim;
     private View mRecentsNoApps;
@@ -164,13 +158,6 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = createView(parent);
-                if (convertView.getParent() != null) {
-                    throw new RuntimeException("Recycled child has parent");
-                }
-            } else {
-                if (convertView.getParent() != null) {
-                    throw new RuntimeException("Recycled child has parent");
-                }
             }
             ViewHolder holder = (ViewHolder) convertView.getTag();
 
@@ -366,11 +353,6 @@
         return mShowing;
     }
 
-    public void setBar(BaseStatusBar bar) {
-        mBar = bar;
-
-    }
-
     public void setStatusBarView(View statusBarView) {
         if (mStatusBarTouchProxy != null) {
             mStatusBarTouchProxy.setStatusBar(statusBarView);
@@ -600,6 +582,9 @@
             usingDrawingCache = true;
         }
 
+        if (bm == null) {
+            throw new RuntimeException("Recents thumbnail is null");
+        }
         ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
                 holder.thumbnailViewImage, bm, 0, 0, null);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 106ce7e..97034bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -488,11 +488,18 @@
                         .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
                 float thumbHeight = res
                         .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
+                if (first == null) {
+                    throw new RuntimeException("Recents thumbnail is null");
+                }
                 if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
                     first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
                             true);
+                    if (first == null) {
+                        throw new RuntimeException("Recents thumbnail is null");
+                    }
                 }
 
+
                 DisplayMetrics dm = new DisplayMetrics();
                 mDisplay.getMetrics(dm);
                 // calculate it here, but consider moving it elsewhere
@@ -521,8 +528,7 @@
                             + thumbBgPadding + thumbLeftMargin);
                     y = (int) (dm.heightPixels
                             - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height) - thumbBgPadding);
-                } else { // if (config.orientation ==
-                         // Configuration.ORIENTATION_LANDSCAPE) {
+                } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                     float thumbTopMargin = res
                             .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_top_margin);
                     float thumbBgPadding = res
@@ -588,25 +594,11 @@
                  break;
              case MSG_PRELOAD_RECENT_APPS:
                   if (DEBUG) Slog.d(TAG, "preloading recents");
-                  {
-                      // TODO:
-                      // need to implement this
-                      //final RecentsPanelView recentsPanel = getRecentsPanel();
-                      //if (recentsPanel != null) {
-                      //recentsPanel.preloadRecentTasksList();
-                      //}
-                  }
+                  getRecentTasksLoader().preloadRecentTasksList();
                   break;
              case MSG_CANCEL_PRELOAD_RECENT_APPS:
                   if (DEBUG) Slog.d(TAG, "cancel preloading recents");
-                  {
-                      // TODO:
-                      // need to implement this
-                      //final RecentsPanelView recentsPanel = getRecentsPanel();
-                      //if (recentsPanel != null) {
-                      //recentsPanel.clearRecentTasksList();
-                      //}
-                  }
+                  getRecentTasksLoader().cancelPreloadingRecentTasksList();
                   break;
              case MSG_OPEN_SEARCH_PANEL:
                  if (DEBUG) Slog.d(TAG, "opening search panel");
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 433d3fe..8f2bae5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -504,19 +504,6 @@
         return lp;
     }
 
-    /*
-    protected void updateRecentsPanel() {
-        super.updateRecentsPanel(R.layout.status_bar_recent_panel);
-        // Make .03 alpha the minimum so you always see the item a bit-- slightly below
-        // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks
-        // a bit jarring
-        mRecentsPanel.setMinSwipeAlpha(0.03f);
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
-        }
-    }
-    */
-
     @Override
     protected void updateSearchPanel() {
         super.updateSearchPanel();
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 8ca3a9c..7153ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -355,7 +355,7 @@
 
         mWindowManager.addView(mCompatModePanel, lp);
 
-        //mRecentButton.setOnTouchListener(mRecentsPanel); //TODO: plumb this
+        mRecentButton.setOnTouchListener(getRecentTasksLoader());
 
         mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
         mPile.removeAllViews();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 3e96f9bc..e761847 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2841,7 +2841,7 @@
             mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
             mDecor.setIsRootNamespace(true);
             mDecor.setLayoutDirection(
-                    getContext().getResources().getConfiguration().layoutDirection);
+                    getContext().getResources().getConfiguration().getLayoutDirection());
         }
         if (mContentParent == null) {
             mContentParent = generateLayout(mDecor);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 2551c04e..e0ba211 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -172,7 +172,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mAppWidgetHost.startListening();
-        populateWidgets();
+        maybePopulateWidgets();
     }
 
     @Override
@@ -581,7 +581,12 @@
         addWidget(view);
     }
 
-    private void populateWidgets() {
+    private void maybePopulateWidgets() {
+        if (mLockPatternUtils.getDevicePolicyManager().getKeyguardWidgetsDisabled(null)
+                != DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_NONE) {
+            Log.v(TAG, "Keyguard widgets disabled because of device policy admin");
+            return;
+        }
         SharedPreferences prefs = mContext.getSharedPreferences(
                 KEYGUARD_WIDGET_PREFS, Context.MODE_PRIVATE);
         for (String key : prefs.getAll().keySet()) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index 6938561..b2ce73e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -256,12 +256,10 @@
 
     private void verifyPasswordAndUnlock() {
         String entry = mPasswordEntry.getText().toString();
-        boolean wrongPassword = true;
         if (mLockPatternUtils.checkPassword(entry)) {
             mCallback.reportSuccessfulUnlockAttempt();
             KeyStore.getInstance().password(entry);
             mCallback.dismiss(true);
-            wrongPassword = false;
         } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
             // to avoid accidental lockout, only count attempts that are long enough to be a
             // real password. This may require some tweaking.
@@ -271,9 +269,9 @@
                 long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
                 handleAttemptLockout(deadline);
             }
+            mNavigationManager.setMessage(
+                    mIsAlpha ? R.string.kg_wrong_password : R.string.kg_wrong_pin);
         }
-        mNavigationManager.setMessage(wrongPassword ?
-                (mIsAlpha ? R.string.kg_wrong_password : R.string.kg_wrong_pin) : 0);
         mPasswordEntry.setText("");
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
index 294ea5c..4861b78 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
@@ -91,8 +91,6 @@
                 }
             });
         }
-
-        setFocusableInTouchMode(true);
         reset();
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index 06ed88a..20fad0b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -119,7 +119,7 @@
         mDateView = (TextView) findViewById(R.id.date);
         mStatus1View = (TextView) findViewById(R.id.status1);
         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
-        mOwnerInfoView = (TextView) findViewById(R.id.propertyOf);
+        mOwnerInfoView = (TextView) findViewById(R.id.owner_info);
         mDigitalClock = (DigitalClock) findViewById(R.id.time);
 
         // Registering this callback immediately updates the battery state, among other things.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
index 409f87b..b6ffde0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java
@@ -179,7 +179,7 @@
         mDateView = (TextView) findViewById(R.id.date);
         mStatus1View = (TextView) findViewById(R.id.status1);
         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
-        mOwnerInfoView = (TextView) findViewById(R.id.propertyOf);
+        mOwnerInfoView = (TextView) findViewById(R.id.owner_info);
         mTransportView = (TransportControlView) findViewById(R.id.transport);
         mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
         mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen;
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index b869abd..343e70d 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -27,7 +27,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -151,13 +150,13 @@
         // Register for the boot completed broadcast, so we can send the
         // ENABLE broacasts. If we try to send them now, they time out,
         // because the system isn't ready to handle them yet.
-        mContext.registerReceiver(mBroadcastReceiver,
+        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
 
         // Register for configuration changes so we can update the names
         // of the widgets when the locale changes.
-        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
-                Intent.ACTION_CONFIGURATION_CHANGED), null, null);
+        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
 
         // Register for broadcasts about package install, etc., so we can
         // update the provider list.
@@ -166,12 +165,14 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
-        mContext.registerReceiver(mBroadcastReceiver, filter);
+        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                filter, null, null);
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                sdFilter, null, null);
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
@@ -181,6 +182,15 @@
                 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
             }
         }, userFilter);
+
+        IntentFilter userStopFilter = new IntentFilter();
+        userStopFilter.addAction(Intent.ACTION_USER_STOPPED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserStopped(getSendingUserId());
+            }
+        }, UserHandle.ALL, userFilter, null, null);
     }
 
     @Override
@@ -254,6 +264,9 @@
         }
     }
 
+    public void onUserStopped(int userId) {
+    }
+
     private AppWidgetServiceImpl getImplForUser(int userId) {
         AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
         if (service == null) {
@@ -370,9 +383,17 @@
                     service.onConfigurationChanged();
                 }
             } else {
-                for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                    service.onBroadcastReceived(intent);
+                int sendingUser = getSendingUserId();
+                if (sendingUser == UserHandle.USER_ALL) {
+                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                        service.onBroadcastReceived(intent);
+                    }
+                } else {
+                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
+                    if (service != null) {
+                        service.onBroadcastReceived(intent);
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index f0989e7..fe8529b 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -116,6 +116,7 @@
 
     private int mLowBatteryWarningLevel;
     private int mLowBatteryCloseWarningLevel;
+    private int mShutdownBatteryTemperature;
 
     private int mPlugType;
     private int mLastPlugType = -1; // Extra state so we can detect first run
@@ -138,6 +139,8 @@
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
         mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
+        mShutdownBatteryTemperature = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_shutdownBatteryTemperature);
 
         mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
 
@@ -228,9 +231,11 @@
     }
 
     private final void shutdownIfOverTemp() {
-        // shut down gracefully if temperature is too high (> 68.0C)
-        // wait until the system has booted before attempting to display the shutdown dialog.
-        if (mBatteryTemperature > 680 && ActivityManagerNative.isSystemReady()) {
+        // shut down gracefully if temperature is too high (> 68.0C by default)
+        // wait until the system has booted before attempting to display the
+        // shutdown dialog.
+        if (mBatteryTemperature > mShutdownBatteryTemperature
+                && ActivityManagerNative.isSystemReady()) {
             Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
             intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -259,7 +264,7 @@
         } else {
             mPlugType = BATTERY_PLUGGED_NONE;
         }
-        
+
         // Let the battery stats keep track of the current level.
         try {
             mBatteryStats.setBatteryState(mBatteryStatus, mBatteryHealth,
@@ -268,7 +273,7 @@
         } catch (RemoteException e) {
             // Should never happen.
         }
-        
+
         shutdownIfNoPower();
         shutdownIfOverTemp();
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 04991bb..cbbfda1 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1852,8 +1852,13 @@
         Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
         intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
         intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
-        mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
-                RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
+                    RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     /**
@@ -1927,7 +1932,12 @@
                 log("sendStickyBroadcast: action=" + intent.getAction());
             }
 
-            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
@@ -2467,7 +2477,12 @@
          * Connectivity events can happen before boot has completed ...
          */
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     // Caller must grab mDnsLock.
@@ -3112,7 +3127,12 @@
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     private static class SettingsObserver extends ContentObserver {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 77b062c..61517b1 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -177,6 +177,9 @@
         static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
         long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
 
+        static final int DEF_KEYGUARD_WIDGET_DISABLED = 0; // none
+        int disableKeyguardWidgets = DEF_KEYGUARD_WIDGET_DISABLED;
+
         boolean encryptionRequested = false;
         boolean disableCamera = false;
 
@@ -286,6 +289,11 @@
                 out.attribute(null, "value", Boolean.toString(disableCamera));
                 out.endTag(null, "disable-camera");
             }
+            if (disableKeyguardWidgets != DEF_KEYGUARD_WIDGET_DISABLED) {
+                out.startTag(null, "disable-keyguard-widgets");
+                out.attribute(null, "value", Integer.toString(disableKeyguardWidgets));
+                out.endTag(null, "disable-keyguard-widgets");
+            }
         }
 
         void readFromXml(XmlPullParser parser)
@@ -2093,6 +2101,46 @@
         }
     }
 
+    /**
+     * Selectively disable keyguard widgets.
+     */
+    public void setKeyguardWidgetsDisabled(ComponentName who, int which) {
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS);
+            if ((ap.disableKeyguardWidgets & which) != which) {
+                ap.disableKeyguardWidgets |= which;
+                saveSettingsLocked();
+            }
+            syncDeviceCapabilitiesLocked();
+        }
+    }
+
+    /**
+     * Gets the disabled state for widgets in keyguard for the given admin,
+     * or the aggregate of all active admins if who is null.
+     */
+    public int getKeyguardWidgetsDisabled(ComponentName who) {
+        synchronized (this) {
+            if (who != null) {
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+                return (admin != null) ? admin.disableKeyguardWidgets : 0;
+            }
+
+            // Determine whether or not keyguard widgets are disabled for any active admins.
+            final int N = mAdminList.size();
+            int which = 0;
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = mAdminList.get(i);
+                which |= admin.disableKeyguardWidgets;
+            }
+            return which;
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 747cf0b..c685473 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -3579,7 +3579,7 @@
         private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
         private final AtomicFile mAdditionalInputMethodSubtypeFile;
         private final HashMap<String, InputMethodInfo> mMethodMap;
-        private final HashMap<String, List<InputMethodSubtype>> mSubtypesMap =
+        private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
                 new HashMap<String, List<InputMethodSubtype>>();
         public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap) {
             if (methodMap == null) {
@@ -3595,18 +3595,19 @@
             mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile);
             if (!subtypeFile.exists()) {
                 // If "subtypes.xml" doesn't exist, create a blank file.
-                writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
-                        methodMap);
+                writeAdditionalInputMethodSubtypes(
+                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap);
             } else {
-                readAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile);
+                readAdditionalInputMethodSubtypes(
+                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile);
             }
         }
 
         private void deleteAllInputMethodSubtypes(String imiId) {
             synchronized (mMethodMap) {
-                mSubtypesMap.remove(imiId);
-                writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
-                        mMethodMap);
+                mAdditionalSubtypesMap.remove(imiId);
+                writeAdditionalInputMethodSubtypes(
+                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
             }
         }
 
@@ -3619,17 +3620,20 @@
                     final InputMethodSubtype subtype = additionalSubtypes[i];
                     if (!subtypes.contains(subtype)) {
                         subtypes.add(subtype);
+                    } else {
+                        Slog.w(TAG, "Duplicated subtype definition found: "
+                                + subtype.getLocale() + ", " + subtype.getMode());
                     }
                 }
-                mSubtypesMap.put(imi.getId(), subtypes);
-                writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
-                        mMethodMap);
+                mAdditionalSubtypesMap.put(imi.getId(), subtypes);
+                writeAdditionalInputMethodSubtypes(
+                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
             }
         }
 
         public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
             synchronized (mMethodMap) {
-                return mSubtypesMap;
+                return mAdditionalSubtypesMap;
             }
         }
 
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 5993f32..37dae35 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.database.Cursor;
 import android.location.Address;
 import android.location.Criteria;
@@ -87,7 +88,7 @@
  * The service class that manages LocationProviders and issues location
  * updates and alerts.
  */
-public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable {
+public class LocationManagerService extends ILocationManager.Stub implements Runnable {
     private static final String TAG = "LocationManagerService";
     public static final boolean D = false;
 
@@ -207,24 +208,30 @@
         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
         mPackageManager = mContext.getPackageManager();
 
+        mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
+        mBlacklist.init();
+        mLocationFudger = new LocationFudger();
+
         synchronized (mLock) {
             loadProvidersLocked();
         }
-        mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
-        mBlacklist.init();
+
         mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
-        mLocationFudger = new LocationFudger();
 
         // listen for settings changes
-        ContentResolver resolver = mContext.getContentResolver();
-        Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
-                "(" + NameValueTable.NAME + "=?)",
-                new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
-        ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
-                mLocationHandler);
-        settingsCursor.close();
-        query.addObserver(this);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true, 
+                new ContentObserver(mLocationHandler) {
+           @Override
+            public void onChange(boolean selfChange) {
+               synchronized (mLock) {
+                   updateProvidersLocked();
+               }
+            }
+        });
         mPackageMonitor.register(mContext, Looper.myLooper(), true);
+
+        updateProvidersLocked();
     }
 
     private void loadProvidersLocked() {
@@ -299,8 +306,6 @@
         if (mGeocodeProvider == null) {
             Slog.e(TAG,  "no geocoder provider found");
         }
-
-        updateProvidersLocked();
     }
 
     /**
@@ -544,14 +549,6 @@
         }
     }
 
-    /** Settings Observer callback */
-    @Override
-    public void update(Observable o, Object arg) {
-        synchronized (mLock) {
-            updateProvidersLocked();
-        }
-    }
-
     private void addProviderLocked(LocationProviderInterface provider) {
         mProviders.add(provider);
         mProvidersByName.put(provider.getName(), provider);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 590e9d9..e670da0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -116,6 +116,7 @@
 import android.provider.Settings;
 import android.text.format.Time;
 import android.util.EventLog;
+import android.util.LocaleUtil;
 import android.util.Log;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
@@ -153,7 +154,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
@@ -495,7 +495,8 @@
 
         @Override
         protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) {
-            if (userId == UserHandle.USER_ALL || userId == filter.owningUserId) {
+            if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL
+                    || userId == filter.owningUserId) {
                 return super.newResult(filter, match, userId);
             }
             return null;
@@ -1530,7 +1531,8 @@
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
 
         mConfiguration.setToDefaults();
-        mConfiguration.locale = Locale.getDefault();
+        mConfiguration.setLocale(Locale.getDefault());
+
         mConfigurationSeq = mConfiguration.seq = 1;
         mProcessStats.init();
         
@@ -3570,15 +3572,32 @@
     public void closeSystemDialogs(String reason) {
         enforceNotIsolatedCaller("closeSystemDialogs");
 
+        final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
-        synchronized (this) {
-            closeSystemDialogsLocked(uid, reason);
+        try {
+            synchronized (this) {
+                // Only allow this from foreground processes, so that background
+                // applications can't abuse it to prevent system UI from being shown.
+                if (uid >= Process.FIRST_APPLICATION_UID) {
+                    ProcessRecord proc;
+                    synchronized (mPidsSelfLocked) {
+                        proc = mPidsSelfLocked.get(pid);
+                    }
+                    if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        Slog.w(TAG, "Ignoring closeSystemDialogs " + reason
+                                + " from background process " + proc);
+                        return;
+                    }
+                }
+                closeSystemDialogsLocked(reason);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        Binder.restoreCallingIdentity(origId);
     }
 
-    void closeSystemDialogsLocked(int callingUid, String reason) {
+    void closeSystemDialogsLocked(String reason) {
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         if (reason != null) {
@@ -3594,14 +3613,9 @@
             }
         }
 
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            broadcastIntentLocked(null, null, intent, null,
-                    null, 0, null, null, null, false, false, -1,
-                    callingUid, UserHandle.USER_ALL);
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
+        broadcastIntentLocked(null, null, intent, null,
+                null, 0, null, null, null, false, false, -1,
+                Process.SYSTEM_UID, UserHandle.USER_ALL);
     }
 
     public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
@@ -7549,7 +7563,7 @@
                             finisher = new IIntentReceiver.Stub() {
                                 public void performReceive(Intent intent, int resultCode,
                                         String data, Bundle extras, boolean ordered,
-                                        boolean sticky) {
+                                        boolean sticky, int sendingUser) {
                                     // The raw IIntentReceiver interface is called
                                     // with the AM lock held, so redispatch to
                                     // execute our code without the lock.
@@ -11038,9 +11052,10 @@
     }
 
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
-            IIntentReceiver receiver, IntentFilter filter, String permission) {
+            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
         enforceNotIsolatedCaller("registerReceiver");
         int callingUid;
+        int callingPid;
         synchronized(this) {
             ProcessRecord callerApp = null;
             if (caller != null) {
@@ -11057,11 +11072,16 @@
                             + " is not running in process " + callerApp);
                 }
                 callingUid = callerApp.info.uid;
+                callingPid = callerApp.pid;
             } else {
                 callerPackage = null;
                 callingUid = Binder.getCallingUid();
+                callingPid = Binder.getCallingPid();
             }
 
+            userId = this.handleIncomingUserLocked(callingPid, callingUid, userId,
+                    true, true, "registerReceiver", callerPackage);
+
             List allSticky = null;
 
             // Look for any matching sticky broadcasts...
@@ -11095,9 +11115,8 @@
             ReceiverList rl
                 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
             if (rl == null) {
-                rl = new ReceiverList(this, callerApp,
-                        Binder.getCallingPid(),
-                        Binder.getCallingUid(), receiver);
+                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
+                        userId, receiver);
                 if (rl.app != null) {
                     rl.app.receivers.add(rl);
                 } else {
@@ -11109,9 +11128,21 @@
                     rl.linkedToDeath = true;
                 }
                 mRegisteredReceivers.put(receiver.asBinder(), rl);
+            } else if (rl.uid != callingUid) {
+                throw new IllegalArgumentException(
+                        "Receiver requested to register for uid " + callingUid
+                        + " was previously registered for uid " + rl.uid);
+            } else if (rl.pid != callingPid) {
+                throw new IllegalArgumentException(
+                        "Receiver requested to register for pid " + callingPid
+                        + " was previously registered for pid " + rl.pid);
+            } else if (rl.userId != userId) {
+                throw new IllegalArgumentException(
+                        "Receiver requested to register for user " + userId
+                        + " was previously registered for user " + rl.userId);
             }
             BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
-                    permission, callingUid);
+                    permission, callingUid, userId);
             rl.add(bf);
             if (!bf.debugCheck()) {
                 Slog.w(TAG, "==> For Dynamic broadast");
@@ -13834,7 +13865,7 @@
                     final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
                         @Override
                         public void performReceive(Intent intent, int resultCode, String data,
-                                Bundle extras, boolean ordered, boolean sticky) {
+                                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                             finishUserStop(uss);
                         }
                     };
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index b0ccd8f..07440b5 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import android.content.IntentFilter;
-import android.os.UserHandle;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 
@@ -32,13 +31,13 @@
     final int owningUserId;
 
     BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
-            String _packageName, String _requiredPermission, int _owningUid) {
+            String _packageName, String _requiredPermission, int _owningUid, int _userId) {
         super(_filter);
         receiverList = _receiverList;
         packageName = _packageName;
         requiredPermission = _requiredPermission;
         owningUid = _owningUid;
-        owningUserId = UserHandle.getUserId(owningUid);
+        owningUserId = _userId;
     }
     
     public void dump(PrintWriter pw, String prefix) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 34dec3a..1b6ff7a 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -222,7 +222,7 @@
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
-                    r.resultCode, r.resultData, r.resultExtras, r.ordered);
+                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId);
             if (DEBUG_BROADCAST)  Slog.v(TAG,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
@@ -357,15 +357,16 @@
 
     private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
-            boolean ordered, boolean sticky) throws RemoteException {
+            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
         // Send the intent to the receiver asynchronously using one-way binder calls.
         if (app != null && app.thread != null) {
             // If we have an app thread, do the call through that so it is
             // correctly ordered with other one-way calls.
             app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky);
+                    data, extras, ordered, sticky, sendingUser);
         } else {
-            receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
+            receiver.performReceive(intent, resultCode, data, extras, ordered,
+                    sticky, sendingUser);
         }
     }
 
@@ -428,8 +429,8 @@
                             + " (seq=" + seq + "): " + r);
                 }
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                    new Intent(r.intent), r.resultCode,
-                    r.resultData, r.resultExtras, r.ordered, r.initialSticky);
+                    new Intent(r.intent), r.resultCode, r.resultData,
+                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
                 if (ordered) {
                     r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                 }
@@ -579,7 +580,7 @@
                             }
                             performReceiveLocked(r.callerApp, r.resultTo,
                                 new Intent(r.intent), r.resultCode,
-                                r.resultData, r.resultExtras, false, false);
+                                r.resultData, r.resultExtras, false, false, r.userId);
                             // Set this to null so that the reference
                             // (local and remote) isnt kept in the mBroadcastHistory.
                             r.resultTo = null;
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 37e9017..0f72409 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -285,7 +285,7 @@
                 if (sendFinish) {
                     try {
                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
-                                null, null, false, false);
+                                null, null, false, false, key.userId);
                     } catch (RemoteException e) {
                     }
                 }
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java
index 32c24c6..9b6701e 100644
--- a/services/java/com/android/server/am/ReceiverList.java
+++ b/services/java/com/android/server/am/ReceiverList.java
@@ -39,18 +39,20 @@
     public final ProcessRecord app;
     public final int pid;
     public final int uid;
+    public final int userId;
     BroadcastRecord curBroadcast = null;
     boolean linkedToDeath = false;
 
     String stringName;
     
     ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
-            int _pid, int _uid, IIntentReceiver _receiver) {
+            int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
         owner = _owner;
         receiver = _receiver;
         app = _app;
         pid = _pid;
         uid = _uid;
+        userId = _userId;
     }
 
     // Want object identity, not the array identity we are inheriting.
@@ -67,8 +69,9 @@
     }
     
     void dumpLocal(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("app="); pw.print(app);
-            pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.println(uid);
+        pw.print(prefix); pw.print("app="); pw.print(app.toShortString());
+            pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid);
+            pw.print(" user="); pw.println(userId);
         if (curBroadcast != null || linkedToDeath) {
             pw.print(prefix); pw.print("curBroadcast="); pw.print(curBroadcast);
                 pw.print(" linkedToDeath="); pw.println(linkedToDeath);
@@ -103,6 +106,8 @@
         sb.append((app != null ? app.processName : "(unknown name)"));
         sb.append('/');
         sb.append(uid);
+        sb.append("/u");
+        sb.append(userId);
         sb.append((receiver.asBinder() instanceof Binder) ? " local:" : " remote:");
         sb.append(Integer.toHexString(System.identityHashCode(receiver.asBinder())));
         sb.append('}');
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index 69d8385..bdc87f9 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -38,8 +38,8 @@
     // the display manager service.  The display device shouldn't really be looking at these.
     private int mCurrentLayerStack = -1;
     private int mCurrentOrientation = -1;
-    private Rect mCurrentViewport;
-    private Rect mCurrentFrame;
+    private Rect mCurrentLayerStackRect;
+    private Rect mCurrentDisplayRect;
 
     // The display device does own its surface texture, but it should only set it
     // within a transaction from performTraversalInTransactionLocked.
@@ -117,44 +117,26 @@
     }
 
     /**
-     * Sets the display orientation while in a transaction.
+     * Sets the display projection while in a transaction.
+     *
+     * @param orientation defines the display's orientation
+     * @param layerStackRect defines which area of the window manager coordinate
+     *            space will be used
+     * @param displayRect defines where on the display will layerStackRect be
+     *            mapped to. displayRect is specified post-orientation, that is
+     *            it uses the orientation seen by the end-user
      */
-    public final void setOrientationInTransactionLocked(int orientation) {
-        if (mCurrentOrientation == orientation) {
-            return;
-        }
+    public final void setProjectionInTransactionLocked(int orientation, Rect layerStackRect, Rect displayRect) {
         mCurrentOrientation = orientation;
-        Surface.setDisplayOrientation(mDisplayToken, orientation);
-    }
-
-    /**
-     * Sets the display viewport while in a transaction.
-     */
-    public final void setViewportInTransactionLocked(Rect viewport) {
-        if (mCurrentViewport != null) {
-            if (mCurrentViewport.equals(viewport)) {
-                return;
-            }
-        } else {
-            mCurrentViewport = new Rect();
+        if (mCurrentLayerStackRect == null) {
+            mCurrentLayerStackRect = new Rect();
         }
-        mCurrentViewport.set(viewport);
-        Surface.setDisplayViewport(mDisplayToken, viewport);
-    }
-
-    /**
-     * Sets the display frame while in a transaction.
-     */
-    public final void setFrameInTransactionLocked(Rect frame) {
-        if (mCurrentFrame != null) {
-            if (mCurrentFrame.equals(frame)) {
-                return;
-            }
-        } else {
-            mCurrentFrame = new Rect();
+        mCurrentLayerStackRect.set(layerStackRect);
+        if (mCurrentDisplayRect == null) {
+            mCurrentDisplayRect = new Rect();
         }
-        mCurrentFrame.set(frame);
-        Surface.setDisplayFrame(mDisplayToken, frame);
+        mCurrentDisplayRect.set(displayRect);
+        Surface.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
     }
 
     /**
@@ -176,8 +158,8 @@
         pw.println("mAdapter=" + mDisplayAdapter.getName());
         pw.println("mCurrentLayerStack=" + mCurrentLayerStack);
         pw.println("mCurrentOrientation=" + mCurrentOrientation);
-        pw.println("mCurrentViewport=" + mCurrentViewport);
-        pw.println("mCurrentFrame=" + mCurrentFrame);
+        pw.println("mCurrentViewport=" + mCurrentLayerStackRect);
+        pw.println("mCurrentFrame=" + mCurrentDisplayRect);
         pw.println("mCurrentSurfaceTexture=" + mCurrentSurfaceTexture);
     }
 }
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 32ca1c5..c864189 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -64,7 +64,8 @@
     private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
 
     // Temporary rectangle used when needed.
-    private final Rect mTempRect = new Rect();
+    private final Rect mTempLayerStackRect = new Rect();
+    private final Rect mTempDisplayRect = new Rect();
 
     public LogicalDisplay(int layerStack, DisplayDevice primaryDisplayDevice) {
         mLayerStack = layerStack;
@@ -208,8 +209,7 @@
         // Set the viewport.
         // This is the area of the logical display that we intend to show on the
         // display device.  For now, it is always the full size of the logical display.
-        mTempRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-        device.setViewportInTransactionLocked(mTempRect);
+        mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
 
         // Set the orientation.
         // The orientation specifies how the physical coordinate system of the display
@@ -219,7 +219,6 @@
                 && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION) != 0) {
             orientation = displayInfo.rotation;
         }
-        device.setOrientationInTransactionLocked(orientation);
 
         // Set the frame.
         // The frame specifies the rotated physical coordinates into which the viewport
@@ -238,21 +237,23 @@
         // We avoid a division (and possible floating point imprecision) here by
         // multiplying the fractions by the product of their denominators before
         // comparing them.
-        int frameWidth, frameHeight;
+        int displayRectWidth, displayRectHeight;
         if (physWidth * displayInfo.logicalHeight
                 < physHeight * displayInfo.logicalWidth) {
             // Letter box.
-            frameWidth = physWidth;
-            frameHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
+            displayRectWidth = physWidth;
+            displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
         } else {
             // Pillar box.
-            frameWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
-            frameHeight = physHeight;
+            displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
+            displayRectHeight = physHeight;
         }
-        int frameTop = (physHeight - frameHeight) / 2;
-        int frameLeft = (physWidth - frameWidth) / 2;
-        mTempRect.set(frameLeft, frameTop, frameLeft + frameWidth, frameTop + frameHeight);
-        device.setFrameInTransactionLocked(mTempRect);
+        int displayRectTop = (physHeight - displayRectHeight) / 2;
+        int displayRectLeft = (physWidth - displayRectWidth) / 2;
+        mTempDisplayRect.set(displayRectLeft, displayRectTop,
+                displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
+
+        device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
     public void dumpLocked(PrintWriter pw) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 183f8ec..55da11f 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -208,8 +208,7 @@
     /**
      * Whether verification is enabled by default.
      */
-    // STOPSHIP: change this to true
-    private static final boolean DEFAULT_VERIFY_ENABLE = false;
+    private static final boolean DEFAULT_VERIFY_ENABLE = true;
 
     /**
      * The default maximum time to wait for the verification agent to return in
@@ -9635,7 +9634,8 @@
         if (pkgList.size() > 0) {
             sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
                 public void performReceive(Intent intent, int resultCode, String data,
-                        Bundle extras, boolean ordered, boolean sticky) throws RemoteException {
+                        Bundle extras, boolean ordered, boolean sticky,
+                        int sendingUser) throws RemoteException {
                     Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
                             reportStatus ? 1 : 0, 1, keys);
                     mHandler.sendMessage(msg);
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index c25f010..c6b7e0d 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -234,10 +234,8 @@
             return false;
         }
 
-        mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-            mService.debugLayoutRepeats("AppWindowToken", mAnimator.mPendingLayoutChanges);
-        }
+        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
+                "AppWindowToken");
 
         clearAnimation();
         animating = false;
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index afcf339c..87a2880 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -212,5 +212,12 @@
             mDimHeight = dimHeight;
             mDimTarget = dimTarget;
         }
+
+        Parameters(Parameters o) {
+            mDimWinAnimator = o.mDimWinAnimator;
+            mDimWidth = o.mDimWidth;
+            mDimHeight = o.mDimHeight;
+            mDimTarget = o.mDimTarget;
+        }
     }
 }
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 1e1b097..f4964cf 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -64,6 +64,7 @@
 
     // Accessed directly by all users.
     boolean layoutNeeded;
+    int pendingLayoutChanges;
 
     DisplayContent(Display display) {
         mDisplay = display;
@@ -84,6 +85,7 @@
     }
 
     DisplayInfo getDisplayInfo() {
+        mDisplay.getDisplayInfo(mDisplayInfo);
         return mDisplayInfo;
     }
 
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 232f2ed..f0b514c 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -16,12 +16,12 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Surface;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 
-import com.android.internal.policy.impl.PhoneWindowManager;
 import com.android.server.wm.WindowManagerService.AppWindowAnimParams;
 import com.android.server.wm.WindowManagerService.LayoutToAnimatorParams;
 
@@ -47,7 +47,8 @@
 
     int mAdjResult;
 
-    int mPendingLayoutChanges;
+    // Layout changes for individual Displays. Indexed by displayId.
+    SparseIntArray mPendingLayoutChanges = new SparseIntArray();
 
     /** Overall window dimensions */
     int mDw, mDh;
@@ -97,7 +98,7 @@
     static class AnimatorToLayoutParams {
         boolean mUpdateQueued;
         int mBulkUpdateParams;
-        int mPendingLayoutChanges;
+        SparseIntArray mPendingLayoutChanges;
         WindowState mWindowDetachedWallpaper;
     }
     /** Do not modify unless holding mService.mWindowMap or this and mAnimToLayout in that order */
@@ -137,7 +138,7 @@
         final AnimatorToLayoutParams animToLayout = mAnimToLayout;
         synchronized (animToLayout) {
             animToLayout.mBulkUpdateParams = mBulkUpdateParams;
-            animToLayout.mPendingLayoutChanges = mPendingLayoutChanges;
+            animToLayout.mPendingLayoutChanges = mPendingLayoutChanges.clone();
             animToLayout.mWindowDetachedWallpaper = mWindowDetachedWallpaper;
 
             if (!animToLayout.mUpdateQueued) {
@@ -175,7 +176,7 @@
             // Set the new DimAnimator params.
             DimAnimator.Parameters dimParams = layoutToAnim.mDimParams;
             if (dimParams == null) {
-                mDimParams = dimParams;
+                mDimParams = null;
             } else {
                 final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
 
@@ -186,7 +187,7 @@
                 if (newWinAnimator.mSurfaceShown &&
                         (existingDimWinAnimator == null || !existingDimWinAnimator.mSurfaceShown
                         || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-                    mDimParams = dimParams;
+                    mDimParams = new DimAnimator.Parameters(dimParams);
                 }
             }
 
@@ -214,7 +215,8 @@
                     if (!winAnimator.mLastHidden) {
                         winAnimator.hide();
                         mService.dispatchWallpaperVisibility(wallpaper, false);
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     }
                 }
                 token.hidden = true;
@@ -233,11 +235,8 @@
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
-                mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats("appToken " + appAnimator.mAppToken + " done",
-                        mPendingLayoutChanges);
-                }
+                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                        "appToken " + appAnimator.mAppToken + " done");
                 if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                         "updateWindowsApps...: done animating " + appAnimator.mAppToken);
             }
@@ -252,11 +251,8 @@
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
-                mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats("exiting appToken " + appAnimator.mAppToken
-                        + " done", mPendingLayoutChanges);
-                }
+                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                    "exiting appToken " + appAnimator.mAppToken + " done");
                 if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                         "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
             }
@@ -302,10 +298,11 @@
 
                 if (wasAnimating && !winAnimator.mAnimating && mWallpaperTarget == win) {
                     mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
-                    mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
+                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                         mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
-                            mPendingLayoutChanges);
+                            mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
                     }
                 }
 
@@ -315,10 +312,12 @@
                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                                 "Animation started that could impact force hide: " + win);
                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        final int displayId = win.mDisplayContent.getDisplayId();
+                        setPendingLayoutChanges(displayId,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
-                                mPendingLayoutChanges);
+                                mPendingLayoutChanges.get(displayId));
                         }
                         mService.mFocusMayChange = true;
                     }
@@ -377,10 +376,11 @@
                     }
                     if (changed && (flags & FLAG_SHOW_WALLPAPER) != 0) {
                         mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
-                                mPendingLayoutChanges);
+                                mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
                         }
                     }
                 }
@@ -390,10 +390,12 @@
             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                 if (atoken == null || atoken.allDrawn) {
                     if (winAnimator.performShowLocked()) {
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+                        final int displayId = win.mDisplayContent.getDisplayId();
+                        mPendingLayoutChanges.put(displayId,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
-                                mPendingLayoutChanges);
+                                mPendingLayoutChanges.get(displayId));
                         }
                     }
                 }
@@ -536,14 +538,14 @@
                                 + wtoken + " numInteresting=" + wtoken.numInterestingWindows
                                 + " numDrawn=" + wtoken.numDrawnWindows);
                         // This will set mOrientationChangeComplete and cause a pass through layout.
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        setAppLayoutChanges(appAnimator,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                                "testTokenMayBeDrawnLocked: freezingScreen");
                     } else {
-                        mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("testTokenMayBeDrawnLocked",
-                                mPendingLayoutChanges);
-                        }
-
+                        setAppLayoutChanges(appAnimator,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
+                                "testTokenMayBeDrawnLocked");
+ 
                         // We can now show all of the drawn windows!
                         if (!mService.mOpeningApps.contains(wtoken)) {
                             mAnimating |= appAnimator.showAllWindowsLocked();
@@ -557,12 +559,6 @@
     private void performAnimationsLocked(final WinAnimatorList winAnimatorList) {
         updateWindowsLocked(winAnimatorList);
         updateWallpaperLocked(winAnimatorList);
-
-        if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-            mPendingActions |= WALLPAPER_ACTION_PENDING;
-        }
-
-        testTokenMayBeDrawnLocked();
     }
 
     // TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
@@ -571,13 +567,8 @@
         if (!mInitialized) {
             return;
         }
-        for (int i = mWinAnimatorLists.size() - 1; i >= 0; i--) {
-            animateLocked(mWinAnimatorLists.get(i));
-        }
-    }
 
-    private void animateLocked(final WinAnimatorList winAnimatorList) {
-        mPendingLayoutChanges = 0;
+        mPendingLayoutChanges.clear();
         mCurrentTime = SystemClock.uptimeMillis();
         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
         boolean wasAnimating = mAnimating;
@@ -586,25 +577,31 @@
             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
         }
 
-        // Update animations of all applications, including those
-        // associated with exiting/removed apps
+        if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
+                TAG, ">>> OPEN TRANSACTION animateLocked");
         Surface.openTransaction();
-
         try {
             updateWindowsAppsAndRotationAnimationsLocked();
-            performAnimationsLocked(winAnimatorList);
 
-            // THIRD LOOP: Update the surfaces of all windows.
+            for (int i = mWinAnimatorLists.size() - 1; i >= 0; i--) {
+                final WinAnimatorList winAnimatorList = mWinAnimatorLists.get(i);
+
+                // Update animations of all applications, including those
+                // associated with exiting/removed apps
+                performAnimationsLocked(winAnimatorList);
+
+                final int N = winAnimatorList.size();
+                for (int j = 0; j < N; j++) {
+                    winAnimatorList.get(j).prepareSurfaceLocked(true);
+                }
+            }
+
+            testTokenMayBeDrawnLocked();
 
             if (mScreenRotationAnimation != null) {
                 mScreenRotationAnimation.updateSurfacesInTransaction();
             }
 
-            final int N = winAnimatorList.size();
-            for (int i = 0; i < N; i++) {
-                winAnimatorList.get(i).prepareSurfaceLocked(true);
-            }
-
             if (mDimParams != null) {
                 mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime);
             }
@@ -629,9 +626,18 @@
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
             Surface.closeTransaction();
+            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
+                    TAG, "<<< CLOSE TRANSACTION animateLocked");
         }
 
-        if (mBulkUpdateParams != 0 || mPendingLayoutChanges != 0) {
+        for (int i = mPendingLayoutChanges.size() - 1; i >= 0; i--) {
+            if ((mPendingLayoutChanges.valueAt(i)
+                    & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                mPendingActions |= WALLPAPER_ACTION_PENDING;
+            }
+        }
+
+        if (mBulkUpdateParams != 0 || mPendingLayoutChanges.size() > 0) {
             updateAnimToLayoutLocked();
         }
 
@@ -645,7 +651,8 @@
         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
                 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
-                + " mPendingLayoutChanges=" + Integer.toHexString(mPendingLayoutChanges));
+                + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
+                + Integer.toHexString(mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY)));
         }
     }
 
@@ -705,7 +712,30 @@
         }
     }
 
-    synchronized void clearPendingActions() {
-        mPendingActions = 0;
+    void clearPendingActions() {
+        synchronized (this) {
+            mPendingActions = 0;
+        }
+    }
+
+    void setPendingLayoutChanges(final int displayId, final int changes) {
+        mPendingLayoutChanges.put(displayId, mPendingLayoutChanges.get(displayId) | changes);
+    }
+
+    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
+        // Used to track which displays layout changes have been done.
+        SparseIntArray displays = new SparseIntArray();
+        for (int i = appAnimator.mAllAppWinAnimators.size() - 1; i >= 0; i--) {
+            WindowStateAnimator winAnimator = appAnimator.mAllAppWinAnimators.get(i);
+            final int displayId = winAnimator.mWin.mDisplayContent.getDisplayId();
+            if (displays.indexOfKey(displayId) < 0) {
+                setPendingLayoutChanges(displayId, changes);
+                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                    mService.debugLayoutRepeats(s, mPendingLayoutChanges.get(displayId));
+                }
+                // Keep from processing this display again.
+                displays.put(displayId, changes);
+            }
+        }
     }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b7eeb69..c82fa55 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -99,7 +99,6 @@
 import android.util.FloatMath;
 import android.util.Log;
 import android.util.SparseArray;
-//import android.util.LogPrinter;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -454,8 +453,6 @@
     int mSystemDecorLayer = 0;
     final Rect mScreenRect = new Rect();
 
-    int mPendingLayoutChanges = 0;
-    boolean mLayoutNeeded = true;
     boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
@@ -1769,7 +1766,7 @@
                 token.hidden = !visible;
                 // Need to do a layout to ensure the wallpaper now has the
                 // correct size.
-                mLayoutNeeded = true;
+                getDefaultDisplayContent().layoutNeeded = true;
             }
 
             int curWallpaperIndex = token.windows.size();
@@ -2012,7 +2009,7 @@
                 token.hidden = !visible;
                 // Need to do a layout to ensure the wallpaper now has the
                 // correct size.
-                mLayoutNeeded = true;
+                getDefaultDisplayContent().layoutNeeded = true;
             }
 
             int curWallpaperIndex = token.windows.size();
@@ -2311,7 +2308,7 @@
                 //Slog.i(TAG, "*** Running exit animation...");
                 win.mExiting = true;
                 win.mRemoveOnExit = true;
-                mLayoutNeeded = true;
+                win.mDisplayContent.layoutNeeded = true;
                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                         false /*updateInputWindows*/);
                 performLayoutAndPlaceSurfacesLocked();
@@ -2428,7 +2425,7 @@
 
         if (!mInLayout) {
             assignLayersLocked(windows);
-            mLayoutNeeded = true;
+            win.mDisplayContent.layoutNeeded = true;
             performLayoutAndPlaceSurfacesLocked();
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
@@ -2494,7 +2491,7 @@
                         w.mGivenVisibleInsets.scale(w.mGlobalScale);
                         w.mGivenTouchableRegion.scale(w.mGlobalScale);
                     }
-                    mLayoutNeeded = true;
+                    w.mDisplayContent.layoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
                 }
             }
@@ -2589,7 +2586,7 @@
         window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
                 (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
         window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-        mLayoutNeeded = true;
+        window.mDisplayContent.layoutNeeded = true;
         performLayoutAndPlaceSurfacesLocked();
     }
 
@@ -2857,7 +2854,7 @@
                 }
             }
 
-            mLayoutNeeded = true;
+            win.mDisplayContent.layoutNeeded = true;
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             if (assignLayers) {
                 assignLayersLocked(win.getWindowList());
@@ -2947,7 +2944,7 @@
                 if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                     adjustWallpaperWindowsLocked();
                 }
-                mLayoutNeeded = true;
+                win.mDisplayContent.layoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
             }
         }
@@ -3461,11 +3458,11 @@
                             win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
                                     false);
                             changed = true;
+                            win.mDisplayContent.layoutNeeded = true;
                         }
                     }
 
                     if (changed) {
-                        mLayoutNeeded = true;
                         performLayoutAndPlaceSurfacesLocked();
                         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                                 false /*updateInputWindows*/);
@@ -3721,7 +3718,7 @@
             if (computeScreenConfigurationLocked(mTempConfiguration)) {
                 if (currentConfig.diff(mTempConfiguration) != 0) {
                     mWaitingForConfig = true;
-                    mLayoutNeeded = true;
+                    getDefaultDisplayContent().layoutNeeded = true;
                     startFreezingDisplayLocked(false);
                     config = new Configuration(mTempConfiguration);
                 }
@@ -3807,6 +3804,7 @@
         }
     }
 
+    @Override
     public int getAppOrientation(IApplicationToken token) {
         synchronized(mWindowMap) {
             AppWindowToken wtoken = findAppWindowToken(token.asBinder());
@@ -3818,6 +3816,7 @@
         }
     }
 
+    @Override
     public void setFocusedApp(IBinder token, boolean moveFocusNow) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setFocusedApp()")) {
@@ -3855,6 +3854,7 @@
         }
     }
 
+    @Override
     public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "prepareAppTransition()")) {
@@ -4084,7 +4084,7 @@
 
                         updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                                 true /*updateInputWindows*/);
-                        mLayoutNeeded = true;
+                        getDefaultDisplayContent().layoutNeeded = true;
                         performLayoutAndPlaceSurfacesLocked();
                         Binder.restoreCallingIdentity(origId);
                         return;
@@ -4249,6 +4249,7 @@
                                     WindowManagerPolicy.TRANSIT_ENTER, true);
                         }
                         changed = true;
+                        win.mDisplayContent.layoutNeeded = true;
                     }
                 } else if (win.isVisibleNow()) {
                     if (!runningAppAnimation) {
@@ -4256,6 +4257,7 @@
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
                     }
                     changed = true;
+                    win.mDisplayContent.layoutNeeded = true;
                 }
             }
 
@@ -4277,7 +4279,6 @@
                       + wtoken.hiddenRequested);
 
             if (changed) {
-                mLayoutNeeded = true;
                 mInputMonitor.setUpdateInputWindowsNeededLw();
                 if (performLayout) {
                     updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
@@ -4405,6 +4406,7 @@
                         mInnerFields.mOrientationChangeComplete = false;
                     }
                     unfrozeWindows = true;
+                    w.mDisplayContent.layoutNeeded = true;
                 }
             }
             if (force || unfrozeWindows) {
@@ -4414,7 +4416,6 @@
             }
             if (unfreezeSurfaceNow) {
                 if (unfrozeWindows) {
-                    mLayoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
                 }
                 stopFreezingDisplayLocked();
@@ -4759,13 +4760,15 @@
                         final DisplayContent displayContent = iterator.next();
                         final WindowList windows = displayContent.getWindowList();
                         final int pos = findWindowOffsetLocked(windows, index);
-                        reAddAppWindowsLocked(displayContent, pos, wtoken);
+                        final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
+                        if (pos != newPos) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                     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*/);
@@ -4805,7 +4808,10 @@
             final DisplayContent displayContent = iterator.next();
             final WindowList windows = displayContent.getWindowList();
             final int pos = findWindowOffsetLocked(windows, tokenPos);
-            reAddAppWindowsLocked(displayContent, pos, wtoken);
+            final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
+            if (pos != newPos) {
+                displayContent.layoutNeeded = true;
+            }
 
             if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                     false /*updateInputWindows*/)) {
@@ -4818,7 +4824,6 @@
 
             // Note that the above updateFocusedWindowLocked conditional used to sit here.
 
-            mLayoutNeeded = true;
             if (!mInLayout) {
                 performLayoutAndPlaceSurfacesLocked();
             }
@@ -4847,7 +4852,11 @@
             for (i=0; i<N; i++) {
                 WindowToken token = mTokenMap.get(tokens.get(i));
                 if (token != null) {
-                    pos = reAddAppWindowsLocked(displayContent, pos, token);
+                    final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
+                    if (newPos != pos) {
+                        displayContent.layoutNeeded = true;
+                    }
+                    pos = newPos;
                 }
             }
             if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
@@ -4860,7 +4869,6 @@
 
         // Note that the above updateFocusedWindowLocked used to sit here.
 
-        mLayoutNeeded = true;
         performLayoutAndPlaceSurfacesLocked();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
 
@@ -5654,7 +5662,7 @@
         synchronized(mWindowMap) {
             changed = updateRotationUncheckedLocked(false);
             if (!changed || forceRelayout) {
-                mLayoutNeeded = true;
+                getDefaultDisplayContent().layoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
             }
         }
@@ -5732,7 +5740,7 @@
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000);
         mWaitingForConfig = true;
-        mLayoutNeeded = true;
+        getDefaultDisplayContent().layoutNeeded = true;
         startFreezingDisplayLocked(inTransaction);
         mInputManager.setDisplayOrientation(0, rotation);
 
@@ -6390,7 +6398,8 @@
         sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
         sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
         outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
-        outConfig.screenLayout = sl;
+        outConfig.screenLayout =
+                sl|(outConfig.screenLayout&Configuration.SCREENLAYOUT_LAYOUTDIR_MASK);
     }
 
     private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
@@ -7576,7 +7585,7 @@
         mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mBaseDisplayWidth,
                 displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity);
 
-        mLayoutNeeded = true;
+        displayContent.layoutNeeded = true;
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
@@ -7831,31 +7840,11 @@
         }
 
         try {
-            DisplayContentsIterator iterator = new DisplayContentsIterator();
-            while (iterator.hasNext()) {
-                final DisplayContent displayContent = iterator.next();
-                performLayoutAndPlaceSurfacesLockedInner(displayContent, recoveringMemory);
-
-                final int N = mPendingRemove.size();
-                if (N > 0) {
-                    if (mPendingRemoveTmp.length < N) {
-                        mPendingRemoveTmp = new WindowState[N+10];
-                    }
-                    mPendingRemove.toArray(mPendingRemoveTmp);
-                    mPendingRemove.clear();
-                    for (int i=0; i<N; i++) {
-                        WindowState w = mPendingRemoveTmp[i];
-                        removeWindowInnerLocked(w.mSession, w);
-                    }
-
-                    assignLayersLocked(displayContent.getWindowList());
-                    mLayoutNeeded = true;
-                }
-            }
+            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
 
             mInLayout = false;
 
-            if (mLayoutNeeded) {
+            if (needsLayout()) {
                 if (++mLayoutRepeatCount < 6) {
                     requestTraversalLocked();
                 } else {
@@ -7880,11 +7869,11 @@
 
     private final void performLayoutLockedInner(final DisplayContent displayContent,
                                     boolean initial, boolean updateInputWindows) {
-        if (!mLayoutNeeded) {
+        if (!displayContent.layoutNeeded) {
             return;
         }
+        displayContent.layoutNeeded = false;
         WindowList windows = displayContent.getWindowList();
-        mLayoutNeeded = false;
 
         DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
@@ -7901,7 +7890,7 @@
         if (DEBUG_LAYOUT) {
             Slog.v(TAG, "-------------------------------------");
             Slog.v(TAG, "performLayout: needed="
-                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
+                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
         }
 
         WindowStateAnimator universeBackground = null;
@@ -8046,8 +8035,7 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @param windows TODO(cmautner):
-     *
+     * @param windows List of windows on default display.
      * @return bitmap indicating if another pass through layout must be made.
      */
     public int handleAppTransitionReadyLocked(WindowList windows) {
@@ -8303,7 +8291,7 @@
             // a new layout to get them all up-to-date.
             changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
                     | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-            mLayoutNeeded = true;
+            getDefaultDisplayContent().layoutNeeded = true;
 
             // TODO(multidisplay): IMEs are only supported on the default display.
             if (windows == getDefaultWindowList() && !moveInputMethodWindowsIfNeededLocked(true)) {
@@ -8525,8 +8513,7 @@
     }
 
     // "Something has changed!  Let's make it correct now."
-    private final void performLayoutAndPlaceSurfacesLockedInner(
-            final DisplayContent displayContent, boolean recoveringMemory) {
+    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
         if (DEBUG_WINDOW_TRACE) {
             Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
                     + Debug.getCallers(3));
@@ -8536,13 +8523,7 @@
             return;
         }
 
-        final WindowList windows = displayContent.getWindowList();
         final long currentTime = SystemClock.uptimeMillis();
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
-        final int innerDw = displayInfo.appWidth;
-        final int innerDh = displayInfo.appHeight;
 
         int i;
 
@@ -8567,201 +8548,233 @@
         mInnerFields.mButtonBrightness = -1;
         mTransactionSequence++;
 
+        final DisplayContent defaultDisplay = getDefaultDisplayContent();
+        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
+        final int defaultDw = defaultInfo.logicalWidth;
+        final int defaultDh = defaultInfo.logicalHeight;
+        final int defaultInnerDw = defaultInfo.appWidth;
+        final int defaultInnerDh = defaultInfo.appHeight;
+
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
-
         Surface.openTransaction();
         try {
+
             if (mWatermark != null) {
-                mWatermark.positionSurface(dw, dh);
+                mWatermark.positionSurface(defaultDw, defaultDh);
             }
             if (mStrictModeFlash != null) {
-                mStrictModeFlash.positionSurface(dw, dh);
+                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
             }
 
             // Give the display manager a chance to adjust properties
             // like display rotation if it needs to.
             mDisplayManagerService.performTraversalInTransactionFromWindowManager();
 
-            int repeats = 0;
-
-            do {
-                repeats++;
-                if (repeats > 6) {
-                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
-                    mLayoutNeeded = false;
-                    break;
-                }
-
-                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
-                    mPendingLayoutChanges);
-
-                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                    if ((adjustWallpaperWindowsLocked() & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
-                        assignLayersLocked(windows);
-                        mLayoutNeeded = true;
-                    }
-                }
-
-                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                    if (updateOrientationFromAppTokensLocked(true)) {
-                        mLayoutNeeded = true;
-                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                    }
-                }
-
-                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
-                    mLayoutNeeded = true;
-                }
-
-                // FIRST LOOP: Perform a layout, if needed.
-                if (repeats < 4) {
-                    performLayoutLockedInner(displayContent, repeats == 1, false /*updateInputWindows*/);
-                } else {
-                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
-                }
-
-                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
-                // it is animating.
-                mPendingLayoutChanges = 0;
-                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
-                    mPendingLayoutChanges);
-                mPolicy.beginPostLayoutPolicyLw(dw, dh);
-                for (i = windows.size() - 1; i >= 0; i--) {
-                    WindowState w = windows.get(i);
-                    if (w.mHasSurface) {
-                        mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
-                    }
-                }
-                mPendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
-                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishPostLayoutPolicyLw",
-                    mPendingLayoutChanges);
-            } while (mPendingLayoutChanges != 0);
-
-            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
-
-            mInnerFields.mObscured = false;
-            mInnerFields.mDimming = false;
-            mInnerFields.mSyswin = false;
-
             boolean focusDisplayed = false;
             boolean updateAllDrawn = false;
-            final int N = windows.size();
-            for (i=N-1; i>=0; i--) {
-                WindowState w = windows.get(i);
 
-                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
+            DisplayContentsIterator iterator = new DisplayContentsIterator();
+            while (iterator.hasNext()) {
+                final DisplayContent displayContent = iterator.next();
+                WindowList windows = displayContent.getWindowList();
+                DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                final int displayId = displayContent.getDisplayId();
+                final int dw = displayInfo.logicalWidth;
+                final int dh = displayInfo.logicalHeight;
+                final int innerDw = displayInfo.appWidth;
+                final int innerDh = displayInfo.appHeight;
+                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
 
-                // Update effect.
-                w.mObscured = mInnerFields.mObscured;
-                if (!mInnerFields.mObscured) {
-                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
-                }
-
-                if (obscuredChanged && (mWallpaperTarget == w) && w.isVisibleLw()) {
-                    // This is the wallpaper target and its obscured state
-                    // changed... make sure the current wallaper's visibility
-                    // has been updated accordingly.
-                    updateWallpaperVisibilityLocked();
-                }
-
-                final WindowStateAnimator winAnimator = w.mWinAnimator;
-
-                // If the window has moved due to its containing
-                // content frame changing, then we'd like to animate
-                // it.
-                if (w.mHasSurface && w.shouldAnimateMove()) {
-                    // Frame has moved, containing content frame
-                    // has also moved, and we're not currently animating...
-                    // let's do something.
-                    Animation a = AnimationUtils.loadAnimation(mContext,
-                            com.android.internal.R.anim.window_move_from_decor);
-                    winAnimator.setAnimation(a);
-                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
-                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
-                    try {
-                        w.mClient.moved(w.mFrame.left, w.mFrame.top);
-                    } catch (RemoteException e) {
+                int repeats = 0;
+                do {
+                    repeats++;
+                    if (repeats > 6) {
+                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
+                        displayContent.layoutNeeded = false;
+                        break;
                     }
-                }
 
-                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-                w.mContentChanged = false;
+                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
+                        displayContent.pendingLayoutChanges);
 
-                // Moved from updateWindowsAndWallpaperLocked().
-                if (w.mHasSurface) {
-                    // Take care of the window being ready to display.
-                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
-                        if ((w.mAttrs.flags
-                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
-                                    "First draw done in potential wallpaper target " + w);
-                            mInnerFields.mWallpaperMayChange = true;
-                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                                debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true",
-                                    mPendingLayoutChanges);
-                            }
+                    if (isDefaultDisplay && ((displayContent.pendingLayoutChanges
+                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0)
+                            && ((adjustWallpaperWindowsLocked()
+                                    & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0)) {
+                        assignLayersLocked(windows);
+                        displayContent.layoutNeeded = true;
+                    }
+
+                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
+                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+                        if (updateOrientationFromAppTokensLocked(true)) {
+                            displayContent.layoutNeeded = true;
+                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                         }
                     }
 
-                    winAnimator.setSurfaceBoundaries(recoveringMemory);
-
-                    final AppWindowToken atoken = w.mAppToken;
-                    if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
-                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
-                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
-                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                    if ((displayContent.pendingLayoutChanges
+                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                        displayContent.layoutNeeded = true;
                     }
-                    if (atoken != null
-                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
-                        if (atoken.lastTransactionSequence != mTransactionSequence) {
-                            atoken.lastTransactionSequence = mTransactionSequence;
-                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                            atoken.startingDisplayed = false;
+
+                    // FIRST LOOP: Perform a layout, if needed.
+                    if (repeats < 4) {
+                        performLayoutLockedInner(displayContent, repeats == 1,
+                                false /*updateInputWindows*/);
+                    } else {
+                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
+                    }
+
+                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
+                    // it is animating.
+                    displayContent.pendingLayoutChanges = 0;
+
+                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
+                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
+
+                    mPolicy.beginPostLayoutPolicyLw(dw, dh);
+                    for (i = windows.size() - 1; i >= 0; i--) {
+                        WindowState w = windows.get(i);
+                        if (w.mHasSurface) {
+                            mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
                         }
-                        if ((w.isOnScreen() || winAnimator.mAttrType
-                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
-                                && !w.mExiting && !w.mDestroying) {
-                            if (WindowManagerService.DEBUG_VISIBILITY ||
-                                    WindowManagerService.DEBUG_ORIENTATION) {
-                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
-                                        + ", isAnimating=" + winAnimator.isAnimating());
-                                if (!w.isDrawnLw()) {
-                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
-                                            + " pv=" + w.mPolicyVisibility
-                                            + " mDrawState=" + winAnimator.mDrawState
-                                            + " ah=" + w.mAttachedHidden
-                                            + " th=" + atoken.hiddenRequested
-                                            + " a=" + winAnimator.mAnimating);
+                    }
+                    displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
+                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishPostLayoutPolicyLw",
+                        displayContent.pendingLayoutChanges);
+                } while (displayContent.pendingLayoutChanges != 0);
+
+                mInnerFields.mObscured = false;
+                mInnerFields.mDimming = false;
+                mInnerFields.mSyswin = false;
+
+                // Only used if default window
+                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
+
+                final int N = windows.size();
+                for (i=N-1; i>=0; i--) {
+                    WindowState w = windows.get(i);
+
+                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
+
+                    // Update effect.
+                    w.mObscured = mInnerFields.mObscured;
+                    if (!mInnerFields.mObscured) {
+                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
+                    }
+
+                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
+                            && w.isVisibleLw()) {
+                        // This is the wallpaper target and its obscured state
+                        // changed... make sure the current wallaper's visibility
+                        // has been updated accordingly.
+                        updateWallpaperVisibilityLocked();
+                    }
+
+                    final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+                    // If the window has moved due to its containing
+                    // content frame changing, then we'd like to animate
+                    // it.
+                    if (w.mHasSurface && w.shouldAnimateMove()) {
+                        // Frame has moved, containing content frame
+                        // has also moved, and we're not currently animating...
+                        // let's do something.
+                        Animation a = AnimationUtils.loadAnimation(mContext,
+                                com.android.internal.R.anim.window_move_from_decor);
+                        winAnimator.setAnimation(a);
+                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+                        try {
+                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
+                        } catch (RemoteException e) {
+                        }
+                    }
+
+                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+                    w.mContentChanged = false;
+
+                    // Moved from updateWindowsAndWallpaperLocked().
+                    if (w.mHasSurface) {
+                        // Take care of the window being ready to display.
+                        if (isDefaultDisplay
+                                && winAnimator.commitFinishDrawingLocked(currentTime)) {
+                            if ((w.mAttrs.flags
+                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                                if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
+                                        "First draw done in potential wallpaper target " + w);
+                                mInnerFields.mWallpaperMayChange = true;
+                                displayContent.pendingLayoutChanges |=
+                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                                    debugLayoutRepeats(
+                                        "wallpaper and commitFinishDrawingLocked true",
+                                        displayContent.pendingLayoutChanges);
                                 }
                             }
-                            if (w != atoken.startingWindow) {
-                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
-                                    atoken.numInterestingWindows++;
-                                    if (w.isDrawnLw()) {
-                                        atoken.numDrawnWindows++;
-                                        if (WindowManagerService.DEBUG_VISIBILITY ||
-                                                WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
-                                                "tokenMayBeDrawn: " + atoken
-                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
-                                                + " mAppFreezing=" + w.mAppFreezing);
-                                        updateAllDrawn = true;
+                        }
+
+                        winAnimator.setSurfaceBoundaries(recoveringMemory);
+
+                        final AppWindowToken atoken = w.mAppToken;
+                        if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
+                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
+                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
+                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                        }
+                        if (atoken != null
+                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
+                            if (atoken.lastTransactionSequence != mTransactionSequence) {
+                                atoken.lastTransactionSequence = mTransactionSequence;
+                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                                atoken.startingDisplayed = false;
+                            }
+                            if ((w.isOnScreen() || winAnimator.mAttrType
+                                    == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
+                                    && !w.mExiting && !w.mDestroying) {
+                                if (WindowManagerService.DEBUG_VISIBILITY ||
+                                        WindowManagerService.DEBUG_ORIENTATION) {
+                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+                                            + ", isAnimating=" + winAnimator.isAnimating());
+                                    if (!w.isDrawnLw()) {
+                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
+                                                + " pv=" + w.mPolicyVisibility
+                                                + " mDrawState=" + winAnimator.mDrawState
+                                                + " ah=" + w.mAttachedHidden
+                                                + " th=" + atoken.hiddenRequested
+                                                + " a=" + winAnimator.mAnimating);
                                     }
                                 }
-                            } else if (w.isDrawnLw()) {
-                                atoken.startingDisplayed = true;
+                                if (w != atoken.startingWindow) {
+                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+                                        atoken.numInterestingWindows++;
+                                        if (w.isDrawnLw()) {
+                                            atoken.numDrawnWindows++;
+                                            if (WindowManagerService.DEBUG_VISIBILITY ||
+                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                                                    "tokenMayBeDrawn: " + atoken
+                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
+                                                    + " mAppFreezing=" + w.mAppFreezing);
+                                            updateAllDrawn = true;
+                                        }
+                                    }
+                                } else if (w.isDrawnLw()) {
+                                    atoken.startingDisplayed = true;
+                                }
                             }
                         }
                     }
-                }
 
-                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
-                    focusDisplayed = true;
-                }
+                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
+                            && w.isDisplayedLw()) {
+                        focusDisplayed = true;
+                    }
 
-                updateResizingWindows(w);
+                    updateResizingWindows(w);
+                }
             }
 
             if (updateAllDrawn) {
@@ -8781,13 +8794,15 @@
             Surface.closeTransaction();
         }
 
+        final WindowList defaultWindows = defaultDisplay.getWindowList();
+
         // If we are ready to perform an app transition, check through
         // all of the app tokens to be shown and see if they are ready
         // to go.
         if (mAppTransitionReady) {
-            mPendingLayoutChanges |= handleAppTransitionReadyLocked(windows);
+            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
-                mPendingLayoutChanges);
+                defaultDisplay.pendingLayoutChanges);
         }
 
         mInnerFields.mAdjResult = 0;
@@ -8799,22 +8814,22 @@
             // 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!
-            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
+            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
-                mPendingLayoutChanges);
+                defaultDisplay.pendingLayoutChanges);
         }
 
-        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
-                !mAppTransitionReady) {
+        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
+                && !mAppTransitionReady) {
             // At this point, there was a window with a wallpaper that
             // was force hiding other windows behind it, but now it
             // is going away.  This may be simple -- just animate
             // away the wallpaper and its window -- or it may be
             // hard -- the wallpaper now needs to be shown behind
             // something that was hidden.
-            mPendingLayoutChanges |= animateAwayWallpaperLocked();
+            defaultDisplay.pendingLayoutChanges |= animateAwayWallpaperLocked();
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
-                mPendingLayoutChanges);
+                defaultDisplay.pendingLayoutChanges);
         }
         mInnerFields.mWallpaperForceHidingChanged = false;
 
@@ -8827,26 +8842,27 @@
         if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
             if (DEBUG_WALLPAPER) Slog.v(TAG,
                     "Wallpaper layer changed: assigning layers + relayout");
-            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-            assignLayersLocked(windows);
+            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+            assignLayersLocked(defaultWindows);
         } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
             if (DEBUG_WALLPAPER) Slog.v(TAG,
                     "Wallpaper visibility changed: relayout");
-            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
         }
 
         if (mFocusMayChange) {
             mFocusMayChange = false;
             if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                     false /*updateInputWindows*/)) {
-                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
                 mInnerFields.mAdjResult = 0;
             }
         }
 
-        if (mLayoutNeeded) {
-            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
+        if (needsLayout()) {
+            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
+                    defaultDisplay.pendingLayoutChanges);
         }
 
         if (!mResizingWindows.isEmpty()) {
@@ -8954,11 +8970,16 @@
             mRelayoutWhileAnimating.clear();
         }
 
-        if (wallpaperDestroyed) {
-            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
+        if (wallpaperDestroyed && (adjustWallpaperWindowsLocked() != 0)) {
+            getDefaultDisplayContent().layoutNeeded = true;
         }
-        if (mPendingLayoutChanges != 0) {
-            mLayoutNeeded = true;
+
+        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            DisplayContent displayContent = iterator.next();
+            if (displayContent.pendingLayoutChanges != 0) {
+                displayContent.layoutNeeded = true;
+            }
         }
 
         // Finally update all input windows now that the window changes have stabilized.
@@ -8995,11 +9016,33 @@
             }
         }
 
-        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
-                !mInnerFields.mUpdateRotation) {
+        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
+                && !mInnerFields.mUpdateRotation) {
             checkDrawnWindowsLocked();
         }
 
+        final int N = mPendingRemove.size();
+        if (N > 0) {
+            if (mPendingRemoveTmp.length < N) {
+                mPendingRemoveTmp = new WindowState[N+10];
+            }
+            mPendingRemove.toArray(mPendingRemoveTmp);
+            mPendingRemove.clear();
+            DisplayContentList displayList = new DisplayContentList();
+            for (i = 0; i < N; i++) {
+                WindowState w = mPendingRemoveTmp[i];
+                removeWindowInnerLocked(w.mSession, w);
+                if (!displayList.contains(w.mDisplayContent)) {
+                    displayList.add(w.mDisplayContent);
+                }
+            }
+
+            for (DisplayContent displayContent : displayList) {
+                assignLayersLocked(displayContent.getWindowList());
+                displayContent.layoutNeeded = true;
+            }
+        }
+
         // Check to see if we are now in a state where the screen should
         // be enabled, because the window obscured flags have changed.
         enableScreenIfNeededLocked();
@@ -9007,9 +9050,8 @@
         updateLayoutToAnimationLocked();
 
         if (DEBUG_WINDOW_TRACE) {
-            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
-                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
-                + " animating=" + mAnimator.mAnimating);
+            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
+                    + mAnimator.mAnimating);
         }
     }
 
@@ -9165,6 +9207,16 @@
         setAnimDimParams(null);
     }
 
+    private boolean needsLayout() {
+        DisplayContentsIterator iterator = new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            if (iterator.next().layoutNeeded) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean copyAnimToLayoutParamsLocked() {
         boolean doRequest = false;
         final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
@@ -9197,10 +9249,15 @@
                 mTurnOnScreen = true;
             }
 
-            mPendingLayoutChanges |= animToLayout.mPendingLayoutChanges;
-            if (mPendingLayoutChanges != 0) {
+            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
+            final int count = pendingLayouts.size();
+            if (count > 0) {
                 doRequest = true;
             }
+            for (int i = 0; i < count; ++i) {
+                final DisplayContent displayContent = getDisplayContent(pendingLayouts.keyAt(i));
+                displayContent.pendingLayoutChanges = pendingLayouts.valueAt(i);
+            }
 
             mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
         }
@@ -9336,7 +9393,7 @@
                 if (moveInputMethodWindowsIfNeededLocked(
                         mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
                         mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
-                    mLayoutNeeded = true;
+                    getDefaultDisplayContent().layoutNeeded = true;
                 }
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
@@ -9350,7 +9407,7 @@
 
             if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                 // The change in focus caused us to need to do a layout.  Okay.
-                mLayoutNeeded = true;
+                getDefaultDisplayContent().layoutNeeded = true;
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
                 }
@@ -10012,8 +10069,18 @@
             }
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
-            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
-                    pw.print("mTransactionSequence="); pw.println(mTransactionSequence);
+            if (needsLayout()) {
+                pw.print("  layoutNeeded on displays=");
+                DisplayContentsIterator dcIterator = new DisplayContentsIterator();
+                while (dcIterator.hasNext()) {
+                    final DisplayContent displayContent = dcIterator.next();
+                    if (displayContent.layoutNeeded) {
+                        pw.print(displayContent.getDisplayId());
+                    }
+                }
+                pw.println();
+            }
+            pw.print("mTransactionSequence="); pw.println(mTransactionSequence);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
                     pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index a52e1d7..6711445 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -587,10 +587,12 @@
         }
     }
 
+    @Override
     public int getSystemUiVisibility() {
         return mSystemUiVisibility;
     }
 
+    @Override
     public int getSurfaceLayer() {
         return mLayer;
     }
@@ -598,7 +600,11 @@
     public IApplicationToken getAppToken() {
         return mAppToken != null ? mAppToken.appToken : null;
     }
-    
+
+    public int getDisplayId() {
+        return mDisplayContent.getDisplayId();
+    }
+
     public long getInputDispatchingTimeoutNanos() {
         return mAppToken != null
                 ? mAppToken.inputDispatchingTimeoutNanos
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 1bda22a..9bb7299 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -335,7 +335,7 @@
                         + mWin.mPolicyVisibilityAfterAnim);
             }
             mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
-            mService.mLayoutNeeded = true;
+            mWin.mDisplayContent.layoutNeeded = true;
             if (!mWin.mPolicyVisibility) {
                 if (mService.mCurrentFocus == mWin) {
                     mService.mFocusMayChange = true;
@@ -359,9 +359,10 @@
         }
 
         finishExit();
-        mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+        final int displayId = mWin.mDisplayContent.getDisplayId();
+        mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
-                "WindowStateAnimator", mAnimator.mPendingLayoutChanges);
+                "WindowStateAnimator", mAnimator.mPendingLayoutChanges.get(displayId));
 
         if (mWin.mAppToken != null) {
             mWin.mAppToken.updateReportedVisibilityLocked();
@@ -1106,8 +1107,9 @@
                         "SIZE " + width + "x" + height, null);
                 mSurfaceResized = true;
                 mSurface.setSize(width, height);
-                mAnimator.mPendingLayoutChanges |=
-                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                final int displayId = w.mDisplayContent.getDisplayId();
+                mAnimator.setPendingLayoutChanges(displayId,
+                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
                     final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
                     mService.startDimming(this, w.mExiting ? 0 : w.mAttrs.dimAmount,
@@ -1360,7 +1362,7 @@
                         // do a layout.  If called from within the transaction
                         // loop, this will cause it to restart with a new
                         // layout.
-                        mService.mLayoutNeeded = true;
+                        c.mDisplayContent.layoutNeeded = true;
                     }
                 }
             }
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 9004e10..5c9282e 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -370,6 +370,13 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void unregisterReceiver(BroadcastReceiver receiver) {
         throw new UnsupportedOperationException();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c783ad6..aebc594 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -33,6 +33,15 @@
         <meta-data android:name="android.graphics.renderThread" android:value="true" />
 
         <activity
+                android:name="PathOffsetActivity"
+                android:label="_PathOffset">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="TextPathActivity"
                 android:label="_TextPath">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java
new file mode 100644
index 0000000..fa73de1
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class PathOffsetActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final PathsView view = new PathsView(this);
+        setContentView(view);
+    }
+
+    public class PathsView extends View {
+        private Path mPath;
+        private Paint mPaint;
+
+        public PathsView(Context context) {
+            super(context);
+
+            mPaint = new Paint();
+            mPaint.setStyle(Paint.Style.STROKE);
+            mPaint.setStrokeWidth(3);
+
+            mPath = new Path();
+            mPath.lineTo(100, 100);
+            mPath.lineTo(200, 300);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            mPath.offset(1, 1);
+            mPaint.setColor(Color.RED);
+            canvas.drawPath(mPath, mPaint);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            invalidate();
+            return super.onTouchEvent(event);
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 07626a3..327ff06 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -168,10 +168,10 @@
             mTest = new Vignette(true, true);
             break;
         case 15:
-            mTest = new GroupTest(true);
+            mTest = new GroupTest(false);
             break;
         case 16:
-            mTest = new GroupTest(false);
+            mTest = new GroupTest(true);
             break;
         case 17:
             mTest = new Intrinsics(0);
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 46b8a27..438a670 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -183,6 +183,13 @@
         return 0;
     }
 
+    // layout direction
+    if (getLayoutDirectionName(part.string(), &config)) {
+        *axis = AXIS_LAYOUTDIR;
+        *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
+        return 0;
+    }
+
     // smallest screen dp width
     if (getSmallestScreenWidthDpName(part.string(), &config)) {
         *axis = AXIS_SMALLESTSCREENWIDTHDP;
@@ -309,6 +316,8 @@
         case AXIS_LANGUAGE:
             return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
                 | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
+        case AXIS_LAYOUTDIR:
+            return config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
         case AXIS_SCREENLAYOUTSIZE:
             return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
         case AXIS_ORIENTATION:
@@ -364,7 +373,7 @@
     Vector<String8> parts;
 
     String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
-    String8 touch, key, keysHidden, nav, navHidden, size, vers;
+    String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
     String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
 
     const char *p = dir;
@@ -452,6 +461,18 @@
         //printf("not region: %s\n", part.string());
     }
 
+    if (getLayoutDirectionName(part.string())) {
+        layoutDir = part;
+
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index];
+    } else {
+        //printf("not layout direction: %s\n", part.string());
+    }
+
     if (getSmallestScreenWidthDpName(part.string())) {
         smallestwidthdp = part;
 
@@ -674,6 +695,7 @@
     this->navHidden = navHidden;
     this->navigation = nav;
     this->screenSize = size;
+    this->layoutDirection = layoutDir;
     this->version = vers;
 
     // what is this anyway?
@@ -691,6 +713,8 @@
     s += ",";
     s += this->locale;
     s += ",";
+    s += layoutDirection;
+    s += ",";
     s += smallestScreenWidthDp;
     s += ",";
     s += screenWidthDp;
@@ -747,6 +771,12 @@
         }
         s += locale;
     }
+    if (this->layoutDirection != "") {
+        if (s.length() > 0) {
+            s += "-";
+        }
+        s += layoutDirection;
+    }
     if (this->smallestScreenWidthDp != "") {
         if (s.length() > 0) {
             s += "-";
@@ -958,6 +988,28 @@
     return false;
 }
 
+bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
+{
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_ANY;
+        return true;
+    } else if (strcmp(name, "ltr") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_LTR;
+        return true;
+    } else if (strcmp(name, "rtl") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_RTL;
+        return true;
+    }
+
+    return false;
+}
+
 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
                                      ResTable_config* out)
 {
@@ -1415,6 +1467,7 @@
     int v = mcc.compare(o.mcc);
     if (v == 0) v = mnc.compare(o.mnc);
     if (v == 0) v = locale.compare(o.locale);
+    if (v == 0) v = layoutDirection.compare(o.layoutDirection);
     if (v == 0) v = vendor.compare(o.vendor);
     if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
     if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
@@ -1447,6 +1500,7 @@
     getMccName(mcc.string(), &params);
     getMncName(mnc.string(), &params);
     getLocaleName(locale.string(), &params);
+    getLayoutDirectionName(layoutDirection.string(), &params);
     getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
     getScreenWidthDpName(screenWidthDp.string(), &params);
     getScreenHeightDpName(screenHeightDp.string(), &params);
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d5f296c..5cfa913 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -51,6 +51,7 @@
     AXIS_SMALLESTSCREENWIDTHDP,
     AXIS_SCREENWIDTHDP,
     AXIS_SCREENHEIGHTDP,
+    AXIS_LAYOUTDIR,
     AXIS_VERSION,
 
     AXIS_START = AXIS_MCC,
@@ -95,6 +96,7 @@
     static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL);
     static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL);
     static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL);
+    static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
     int compare(const AaptGroupEntry& o) const;
@@ -133,6 +135,7 @@
     String8 navHidden;
     String8 navigation;
     String8 screenSize;
+    String8 layoutDirection;
     String8 version;
 
     mutable bool mParamsChanged;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index d98fe65..3d7b088 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2811,7 +2811,7 @@
 
                 NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
                      "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                     "sw%ddp w%ddp h%ddp\n",
+                     "sw%ddp w%ddp h%ddp dir:%d\n",
                       ti+1,
                       config.mcc, config.mnc,
                       config.language[0] ? config.language[0] : '-',
@@ -2829,7 +2829,8 @@
                       config.screenHeight,
                       config.smallestScreenWidthDp,
                       config.screenWidthDp,
-                      config.screenHeightDp));
+                      config.screenHeightDp,
+                      config.layoutDirection));
                       
                 if (filterable && !filter.match(config)) {
                     continue;
@@ -2853,7 +2854,7 @@
                 tHeader->config = config;
                 NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
                      "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                     "sw%ddp w%ddp h%ddp\n",
+                     "sw%ddp w%ddp h%ddp dir:%d\n",
                       ti+1,
                       tHeader->config.mcc, tHeader->config.mnc,
                       tHeader->config.language[0] ? tHeader->config.language[0] : '-',
@@ -2871,7 +2872,8 @@
                       tHeader->config.screenHeight,
                       tHeader->config.smallestScreenWidthDp,
                       tHeader->config.screenWidthDp,
-                      tHeader->config.screenHeightDp));
+                      tHeader->config.screenHeightDp,
+                      tHeader->config.layoutDirection));
                 tHeader->config.swapHtoD();
 
                 // Build the entries inside of this type.
@@ -3489,7 +3491,7 @@
         if (config != NULL) {
             NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                    "sw%ddp w%ddp h%ddp\n",
+                    "sw%ddp w%ddp h%ddp dir:%d\n",
                       sourcePos.file.string(), sourcePos.line,
                       config->mcc, config->mnc,
                       config->language[0] ? config->language[0] : '-',
@@ -3506,7 +3508,8 @@
                       config->screenHeight,
                       config->smallestScreenWidthDp,
                       config->screenWidthDp,
-                      config->screenHeightDp));
+                      config->screenHeightDp,
+                      config->layoutDirection));
         } else {
             NOISY(printf("New entry at %s:%d: NULL config\n",
                       sourcePos.file.string(), sourcePos.line));
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
index bd332a6..26cb97b 100644
--- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -31,6 +31,7 @@
  */
 public class SystemClock_Delegate {
     private static long sBootTime = System.currentTimeMillis();
+    private static long sBootTimeNano = System.nanoTime();
 
     @LayoutlibDelegate
     /*package*/ static boolean setCurrentTimeMillis(long millis) {
@@ -60,6 +61,16 @@
     }
 
     /**
+     * Returns nanoseconds since boot, including time spent in sleep.
+     *
+     * @return elapsed nanoseconds since boot.
+     */
+    @LayoutlibDelegate
+    /*package*/ static long elapsedRealtimeNano() {
+        return System.nanoTime() - sBootTimeNano;
+    }
+
+    /**
      * Returns milliseconds running in the current thread.
      *
      * @return elapsed milliseconds in the thread
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
index 1df78c2..8b4c60b 100644
--- a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
@@ -91,4 +91,42 @@
     /*package*/ static float sqrt(float value) {
         return (float)Math.sqrt(value);
     }
+
+    /**
+     * Returns the closest float approximation of the raising "e" to the power
+     * of the argument.
+     *
+     * @param value to compute the exponential of
+     * @return the exponential of value
+     */
+    @LayoutlibDelegate
+    /*package*/ static float exp(float value) {
+        return (float)Math.exp(value);
+    }
+
+    /**
+     * Returns the closest float approximation of the result of raising {@code
+     * x} to the power of {@code y}.
+     *
+     * @param x the base of the operation.
+     * @param y the exponent of the operation.
+     * @return {@code x} to the power of {@code y}.
+     */
+    @LayoutlibDelegate
+    /*package*/ static float pow(float x, float y) {
+        return (float)Math.pow(x, y);
+    }
+
+    /**
+     * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
+     * {@code y}</i><sup>{@code 2}</sup>{@code )}.
+     *
+     * @param x a float number
+     * @param y a float number
+     * @return the hypotenuse
+     */
+    @LayoutlibDelegate
+    /*package*/ static float hypot(float x, float y) {
+        return (float)Math.sqrt(x*x + y*y);
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index e629b75..428c4c2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1164,6 +1164,13 @@
     }
 
     @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
+            IntentFilter arg1, String arg2, Handler arg3) {
+        // pass
+        return null;
+    }
+
+    @Override
     public void removeStickyBroadcast(Intent arg0) {
         // pass