Merge "Escape arguments before passing to netd."
diff --git a/Android.mk b/Android.mk
index d6d01d88..c8576a0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -700,9 +700,6 @@
 
 include $(BUILD_DROIDDOC)
 
-# explicitly specify that online-sdk depends on framework-res and any generated docs
-$(full_target): framework-res-package-target
-
 # ==== docs for the web (on the devsite app engine server) =======================
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
@@ -731,36 +728,6 @@
 
 include $(BUILD_DROIDDOC)
 
-# explicitly specify that ds depends on framework-res and any generated docs
-$(full_target): framework-res-package-target
-
-
-#==== reference docs for GCM =======================
-
-include $(CLEAR_VARS)
-#
-gcm_docs_src_files += \
-        $(call all-java-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-client/src) \
-        $(call all-java-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-server/src) \
-        $(call all-html-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-client/src) \
-        $(call all-html-files-under, ../../vendor/unbundled_google/libs/gcm/gcm-server/src) \
-
-LOCAL_SRC_FILES := $(gcm_docs_src_files)
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE:= online-gcm-ref
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_IS_HOST_MODULE := false
-
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-sdk
-
-LOCAL_DROIDDOC_OPTIONS := \
-        -toroot / \
-        -gcmref \
-        -hdf android.whichdoc online \
-        -hdf template.showLanguageMenu true
-
-include $(BUILD_DROIDDOC)
-
 # ==== docs that have all of the stuff that's @hidden =======================
 include $(CLEAR_VARS)
 
diff --git a/api/current.txt b/api/current.txt
index c8f999f..ee4732d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4153,11 +4153,14 @@
   }
 
   public final class UiAutomation {
-    method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, com.android.internal.util.Predicate<android.view.accessibility.AccessibilityEvent>, long) throws java.util.concurrent.TimeoutException;
+    method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
+    method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
+    method public final boolean performGlobalAction(int);
     method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
     method public boolean setRotation(int);
+    method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public android.graphics.Bitmap takeScreenshot();
     method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
     field public static final int ROTATION_FREEZE_0 = 0; // 0x0
@@ -4168,6 +4171,10 @@
     field public static final int ROTATION_UNFREEZE = -2; // 0xfffffffe
   }
 
+  public static abstract interface UiAutomation.AccessibilityEventFilter {
+    method public abstract boolean accept(android.view.accessibility.AccessibilityEvent);
+  }
+
   public static abstract interface UiAutomation.OnAccessibilityEventListener {
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
   }
@@ -19485,6 +19492,7 @@
 
   public class FieldPacker {
     ctor public FieldPacker(int);
+    ctor public FieldPacker(byte[]);
     method public void addBoolean(boolean);
     method public void addF32(float);
     method public void addF32(android.renderscript.Float2);
@@ -22265,6 +22273,21 @@
     method public int getTopPadding();
   }
 
+  public abstract interface TextDirectionHeuristic {
+    method public abstract boolean isRtl(char[], int, int);
+    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+  }
+
+  public class TextDirectionHeuristics {
+    ctor public TextDirectionHeuristics();
+    field public static final android.text.TextDirectionHeuristic ANYRTL_LTR;
+    field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_LTR;
+    field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_RTL;
+    field public static final android.text.TextDirectionHeuristic LOCALE;
+    field public static final android.text.TextDirectionHeuristic LTR;
+    field public static final android.text.TextDirectionHeuristic RTL;
+  }
+
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -22356,6 +22379,48 @@
 
 }
 
+package android.text.bidi {
+
+  public final class BidiFormatter {
+    method public java.lang.String dirAttr(java.lang.String);
+    method public java.lang.String dirAttr(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String dirAttr(boolean);
+    method public java.lang.String dirAttrValue(java.lang.String);
+    method public java.lang.String dirAttrValue(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String dirAttrValue(boolean);
+    method public java.lang.String endEdge();
+    method public static android.text.bidi.BidiFormatter getInstance(boolean);
+    method public static android.text.bidi.BidiFormatter getInstance(java.util.Locale);
+    method public boolean getStereoReset();
+    method public boolean isRtl(java.lang.String);
+    method public boolean isRtlContext();
+    method public java.lang.String mark();
+    method public java.lang.String markAfter(java.lang.String);
+    method public java.lang.String markAfter(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String markBefore(java.lang.String);
+    method public java.lang.String markBefore(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
+    method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String spanWrap(java.lang.String, boolean);
+    method public java.lang.String spanWrap(java.lang.String);
+    method public java.lang.String startEdge();
+    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String unicodeWrap(java.lang.String, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale);
+    method public android.text.bidi.BidiFormatter build();
+    method public android.text.bidi.BidiFormatter.Builder setTextDirectionHeuristic(android.text.TextDirectionHeuristic);
+    method public android.text.bidi.BidiFormatter.Builder stereoReset(boolean);
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
@@ -23278,6 +23343,7 @@
     field public static final int DENSITY_TV = 213; // 0xd5
     field public static final int DENSITY_XHIGH = 320; // 0x140
     field public static final int DENSITY_XXHIGH = 480; // 0x1e0
+    field public static final int DENSITY_XXXHIGH = 640; // 0x280
     field public float density;
     field public int densityDpi;
     field public int heightPixels;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8dddbc1..811b92a 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -457,7 +457,7 @@
      *
      * @return The accessibility service info.
      *
-     * @see AccessibilityNodeInfo
+     * @see AccessibilityServiceInfo
      */
     public final AccessibilityServiceInfo getServiceInfo() {
         IAccessibilityServiceConnection connection =
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 033a598..d82b9a3 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -399,6 +399,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setComponentName(ComponentName component) {
+        mId = component.flattenToShortString();
+    }
+
+    /**
      * The accessibility service id.
      * <p>
      *   <strong>Generated by the system.</strong>
@@ -515,6 +522,33 @@
     }
 
     @Override
+    public int hashCode() {
+        return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
+        if (mId == null) {
+            if (other.mId != null) {
+                return false;
+            }
+        } else if (!mId.equals(other.mId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder();
         appendEventTypes(stringBuilder, eventTypes);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 594be68..944a533 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1915,7 +1915,30 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
-    /** @hide */
+    /**
+     * @hide
+     * Helper for dealing with incoming user arguments to system service calls.
+     * Takes care of checking permissions and converting USER_CURRENT to the
+     * actual current user.
+     *
+     * @param callingPid The pid of the incoming call, as per Binder.getCallingPid().
+     * @param callingUid The uid of the incoming call, as per Binder.getCallingUid().
+     * @param userId The user id argument supplied by the caller -- this is the user
+     * they want to run as.
+     * @param allowAll If true, we will allow USER_ALL.  This means you must be prepared
+     * to get a USER_ALL returned and deal with it correctly.  If false,
+     * an exception will be thrown if USER_ALL is supplied.
+     * @param requireFull If true, the caller must hold
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} to be able to run as a
+     * different user than their current process; otherwise they must hold
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+     * @param name Optional textual name of the incoming call; only for generating error messages.
+     * @param callerPackage Optional package name of caller; only for error messages.
+     *
+     * @return Returns the user ID that the call should run as.  Will always be a concrete
+     * user number, unless <var>allowAll</var> is true in which case it could also be
+     * USER_ALL.
+     */
     public static int handleIncomingUser(int callingPid, int callingUid, int userId,
             boolean allowAll, boolean requireFull, String name, String callerPackage) {
         if (UserHandle.getUserId(callingUid) == userId) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 34708ab..de69867 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.Manifest;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
 
@@ -29,7 +30,25 @@
 import android.os.Process;
 import android.os.RemoteException;
 
-/** @hide */
+/**
+ * API for interacting with "application operation" tracking.  Allows you to:
+ *
+ * - Note when operations are happening, and find out if they are allowed for the current caller.
+ * - Disallow specific apps from doing specific operations.
+ * - Collect all of the current information about operations that have been executed or are not
+ * being allowed.
+ * - Monitor for changes in whether an operation is allowed.
+ *
+ * Each operation is identified by a single integer; these integers are a fixed set of
+ * operations, enumerated by the OP_* constants.
+ *
+ * When checking operations, the result is a "mode" integer indicating the current setting
+ * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
+ * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
+ * SecurityException back to the caller; the normal operation calls will do this for you).
+ *
+ * @hide
+ */
 public class AppOpsManager {
     final Context mContext;
     final IAppOpsService mService;
@@ -71,8 +90,11 @@
     public static final int OP_WRITE_SETTINGS = 23;
     public static final int OP_SYSTEM_ALERT_WINDOW = 24;
     public static final int OP_ACCESS_NOTIFICATIONS = 25;
+    public static final int OP_CAMERA = 26;
+    public static final int OP_RECORD_AUDIO = 27;
+    public static final int OP_PLAY_AUDIO = 28;
     /** @hide */
-    public static final int _NUM_OP = 26;
+    public static final int _NUM_OP = 29;
 
     /**
      * This maps each operation to the operation that serves as the
@@ -109,6 +131,9 @@
             OP_WRITE_SETTINGS,
             OP_SYSTEM_ALERT_WINDOW,
             OP_ACCESS_NOTIFICATIONS,
+            OP_CAMERA,
+            OP_RECORD_AUDIO,
+            OP_PLAY_AUDIO,
     };
 
     /**
@@ -142,6 +167,9 @@
             "WRITE_SETTINGS",
             "SYSTEM_ALERT_WINDOW",
             "ACCESS_NOTIFICATIONS",
+            "CAMERA",
+            "RECORD_AUDIO",
+            "PLAY_AUDIO",
     };
 
     /**
@@ -175,21 +203,36 @@
             android.Manifest.permission.WRITE_SETTINGS,
             android.Manifest.permission.SYSTEM_ALERT_WINDOW,
             android.Manifest.permission.ACCESS_NOTIFICATIONS,
+            android.Manifest.permission.CAMERA,
+            android.Manifest.permission.RECORD_AUDIO,
+            null, // no permission for playing audio
     };
 
+    /**
+     * Retrieve the op switch that controls the given operation.
+     */
     public static int opToSwitch(int op) {
         return sOpToSwitch[op];
     }
 
+    /**
+     * Retrieve a non-localized name for the operation, for debugging output.
+     */
     public static String opToName(int op) {
         if (op == OP_NONE) return "NONE";
         return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
     }
 
+    /**
+     * Retrieve the permission associated with an operation, or null if there is not one.
+     */
     public static String opToPermission(int op) {
         return sOpPerms[op];
     }
 
+    /**
+     * Class holding all of the operation information associated with an app.
+     */
     public static class PackageOps implements Parcelable {
         private final String mPackageName;
         private final int mUid;
@@ -249,6 +292,9 @@
         };
     }
 
+    /**
+     * Class holding the information about one unique operation of an application.
+     */
     public static class OpEntry implements Parcelable {
         private final int mOp;
         private final int mMode;
@@ -321,6 +367,9 @@
         };
     }
 
+    /**
+     * Callback for notification of changes to operation state.
+     */
     public interface Callback {
         public void opChanged(int op, String packageName);
     }
@@ -330,6 +379,11 @@
         mService = service;
     }
 
+    /**
+     * Retrieve current operation state for all applications.
+     *
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     */
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
         try {
             return mService.getPackagesForOps(ops);
@@ -338,6 +392,13 @@
         return null;
     }
 
+    /**
+     * Retrieve current operation state for one application.
+     *
+     * @param uid The uid of the application of interest.
+     * @param packageName The name of the application of interest.
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     */
     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
         try {
             return mService.getOpsForPackage(uid, packageName, ops);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index bb10f62..1f4c81d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -38,5 +38,6 @@
     boolean areNotificationsEnabledForPackage(String pkg, int uid);
 
     StatusBarNotification[] getActiveNotifications(String callingPkg);
+    StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
 }
 
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index e611f6d..7d02342 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -18,7 +18,9 @@
 
 import android.accessibilityservice.AccessibilityService.Callbacks;
 import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -35,8 +37,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
 
-import com.android.internal.util.Predicate;
-
 import java.util.ArrayList;
 import java.util.concurrent.TimeoutException;
 
@@ -45,7 +45,10 @@
  * introspection of the screen content. It relies on the platform accessibility
  * APIs to introspect the screen and to perform some actions on the remote view
  * tree. It also allows injecting of arbitrary raw input events simulating user
- * interaction with keyboards and touch devices.
+ * interaction with keyboards and touch devices. One can think of a UiAutomation
+ * as a special type of {@link android.accessibilityservice.AccessibilityService}
+ * which does not provide hooks for the service life cycle and exposes other
+ * APIs that are useful for UI test automation.
  * <p>
  * The APIs exposed by this class are low-level to maximize flexibility when
  * developing UI test automation tools and libraries. Generally, a UiAutomation
@@ -130,6 +133,21 @@
     }
 
     /**
+     * Listener for filtering accessibility events.
+     */
+    public static interface AccessibilityEventFilter {
+
+        /**
+         * Callback for determining whether an event is accepted or
+         * it is filtered out.
+         *
+         * @param event The event to process.
+         * @return True if the event is accepted, false to filter it out.
+         */
+        public boolean accept(AccessibilityEvent event);
+    }
+
+    /**
      * Creates a new instance that will handle callbacks from the accessibility
      * layer on the thread of the provided looper and perform requests for privileged
      * operations on the provided connection.
@@ -243,6 +261,90 @@
     }
 
     /**
+     * Performs a global action. Such an action can be performed at any moment
+     * regardless of the current application or user location in that application.
+     * For example going back, going home, opening recents, etc.
+     *
+     * @param action The action to perform.
+     * @return Whether the action was successfully performed.
+     *
+     * @see AccessibilityService#GLOBAL_ACTION_BACK
+     * @see AccessibilityService#GLOBAL_ACTION_HOME
+     * @see AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
+     * @see AccessibilityService#GLOBAL_ACTION_RECENTS
+     */
+    public final boolean performGlobalAction(int action) {
+        final IAccessibilityServiceConnection connection;
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+            connection = AccessibilityInteractionClient.getInstance()
+                    .getConnection(mConnectionId);
+        }
+        // Calling out without a lock held.
+        if (connection != null) {
+            try {
+                return connection.performGlobalAction(action);
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
+     * This method is useful if one wants to change some of the dynamically
+     * configurable properties at runtime.
+     *
+     * @return The accessibility service info.
+     *
+     * @see AccessibilityServiceInfo
+     */
+    public final AccessibilityServiceInfo getServiceInfo() {
+        final IAccessibilityServiceConnection connection;
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+            connection = AccessibilityInteractionClient.getInstance()
+                    .getConnection(mConnectionId);
+        }
+        // Calling out without a lock held.
+        if (connection != null) {
+            try {
+                return connection.getServiceInfo();
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the {@link AccessibilityServiceInfo} that describes how this
+     * UiAutomation will be handled by the platform accessibility layer.
+     *
+     * @param info The info.
+     *
+     * @see AccessibilityServiceInfo
+     */
+    public final void setServiceInfo(AccessibilityServiceInfo info) {
+        final IAccessibilityServiceConnection connection;
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+            AccessibilityInteractionClient.getInstance().clearCache();
+            connection = AccessibilityInteractionClient.getInstance()
+                    .getConnection(mConnectionId);
+        }
+        // Calling out without a lock held.
+        if (connection != null) {
+            try {
+                connection.setServiceInfo(info);
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
+            }
+        }
+    }
+
+    /**
      * Gets the root {@link AccessibilityNodeInfo} in the active window.
      *
      * @return The root info.
@@ -339,7 +441,7 @@
      * @throws TimeoutException If the expected event is not received within the timeout.
      */
     public AccessibilityEvent executeAndWaitForEvent(Runnable command,
-            Predicate<AccessibilityEvent> filter, long timeoutMillis) throws TimeoutException {
+            AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
         synchronized (mLock) {
             throwIfNotConnectedLocked();
 
@@ -363,7 +465,7 @@
                         if (event.getEventTime() <= executionStartTimeMillis) {
                             continue;
                         }
-                        if (filter.apply(event)) {
+                        if (filter.accept(event)) {
                             return event;
                         }
                         event.recycle();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d80598c..c507245 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -666,6 +666,15 @@
     public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
 
     /**
+     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+     * if the system failed to install the package because the user is restricted from installing
+     * apps.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
+
+    /**
      * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
      * package's data directory.
      *
@@ -710,6 +719,15 @@
     public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;
 
     /**
+     * Deletion failed return code: this is passed to the
+     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+     * failed to delete the package since the user is restricted.
+     *
+     * @hide
+     */
+    public static final int DELETE_FAILED_USER_RESTRICTED = -3;
+
+    /**
      * Return code that is passed to the {@link IPackageMoveObserver} by
      * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} when the
      * package has been successfully moved by the system.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7775293..24a0bb5 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -792,6 +792,7 @@
                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
                     + Integer.toHexString(value.type) + " is not valid");
             }
+            mTmpValue = null;
         }
         ColorStateList csl = loadColorStateList(value, id);
         synchronized (mAccessLock) {
@@ -2227,6 +2228,9 @@
             throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
+            if (value == null) {
+                mTmpValue = value = new TypedValue();
+            }
             getValue(id, value, true);
             if (value.type == TypedValue.TYPE_STRING) {
                 return loadXmlResourceParser(value.string.toString(), id,
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index ec02ae0..34c9740 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -17,6 +17,7 @@
 
 package android.os;
 
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
@@ -37,4 +38,6 @@
     void wipeUser(int userHandle);
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
+    Bundle getUserRestrictions(int userHandle);
+    void setUserRestrictions(in Bundle restrictions, int userHandle);
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d73f99a..e4a5e7f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -35,6 +35,42 @@
     private final IUserManager mService;
     private final Context mContext;
 
+    /**
+     * @hide
+     * Key for user restrictions. Specifies if a user is allowed to add or remove accounts.
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String ALLOW_MODIFY_ACCOUNTS = "modify_accounts";
+
+    /**
+     * @hide
+     * Key for user restrictions. Specifies if a user is allowed to change Wi-Fi access points.
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String ALLOW_CONFIG_WIFI = "config_wifi";
+
+    /**
+     * @hide
+     * Key for user restrictions. Specifies if a user is allowed to install applications.
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String ALLOW_INSTALL_APPS = "install_apps";
+
+    /**
+     * @hide
+     * Key for user restrictions. Specifies if a user is allowed to uninstall applications.
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String ALLOW_UNINSTALL_APPS = "uninstall_apps";
+
     /** @hide */
     public UserManager(Context context, IUserManager service) {
         mService = service;
@@ -132,6 +168,35 @@
         }
     }
 
+    /** @hide */
+    public Bundle getUserRestrictions() {
+        return getUserRestrictions(Process.myUserHandle());
+    }
+
+    /** @hide */
+    public Bundle getUserRestrictions(UserHandle userHandle) {
+        try {
+            return mService.getUserRestrictions(userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user restrictions", re);
+            return Bundle.EMPTY;
+        }
+    }
+
+    /** @hide */
+    public void setUserRestrictions(Bundle restrictions) {
+        setUserRestrictions(restrictions, Process.myUserHandle());
+    }
+
+    /** @hide */
+    public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
+        try {
+            mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set user restrictions", re);
+        }
+    }
+
     /**
      * Return the serial number for a user.  This is a device-unique
      * number assigned to that user; if the user is deleted and then a new
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 09ff7be..028317f 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -703,7 +703,13 @@
      * show for the initial UI.
      */
     public Header onGetInitialHeader() {
-        return mHeaders.get(0);
+        for (int i=0; i<mHeaders.size(); i++) {
+            Header h = mHeaders.get(i);
+            if (h.fragment != null) {
+                return h;
+            }
+        }
+        throw new IllegalStateException("Must have at least one header with a fragment");
     }
 
     /**
@@ -1167,6 +1173,9 @@
             getFragmentManager().popBackStack(BACK_STACK_PREFS,
                     FragmentManager.POP_BACK_STACK_INCLUSIVE);
         } else {
+            if (header.fragment == null) {
+                throw new IllegalStateException("can't switch to header that has no fragment");
+            }
             int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
             switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
             setSelectedHeader(header);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3d850cf..25954b9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -50,7 +50,6 @@
 import android.text.TextUtils;
 import android.util.AndroidException;
 import android.util.Log;
-import android.view.WindowOrientationListener;
 
 import com.android.internal.widget.ILockSettings;
 
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 831ccc5..60545e5 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -38,7 +38,7 @@
      * {@hide}
      */
     void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, Paint p);
+            float x, float y, Paint p);
 
    /**
      * Just like {@link Paint#measureText}.
@@ -55,19 +55,12 @@
      * @hide
      */
     float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex, Paint paint);
-
-    /**
-     * Just like {@link Paint#getTextRunAdvances}.
-     * @hide
-     */
-    float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
+            float[] advances, int advancesIndex, Paint paint);
 
     /**
      * Just like {@link Paint#getTextRunCursor}.
      * @hide
      */
-    int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
+    int getTextRunCursor(int contextStart, int contextEnd, int offset,
             int cursorOpt, Paint p);
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index bd9310c1..0c881a4 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -159,18 +159,15 @@
         mPos = p + len;
 
         if (mEasy) {
-            int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
-                ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
-            return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
+            return paint.getTextRunAdvances(mChars, p, len, p, len, mWidths, p);
         }
 
         float totalAdvance = 0;
         int level = mLevels[p];
         for (int q = p, i = p + 1, e = p + len;; ++i) {
             if (i == e || mLevels[i] != level) {
-                int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
                 totalAdvance +=
-                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
+                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, mWidths, q);
                 if (i == e) {
                     break;
                 }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 0f30d25..9e43671 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1130,20 +1130,20 @@
      * {@hide}
      */
     public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, Paint p) {
+            float x, float y, Paint p) {
         checkRange("drawTextRun", start, end);
 
         int contextLen = contextEnd - contextStart;
         int len = end - start;
         if (contextEnd <= mGapStart) {
-            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
+            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, p);
         } else if (contextStart >= mGapStart) {
             c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
-                    contextLen, x, y, flags, p);
+                    contextLen, x, y, p);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
-            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
+            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, p);
             TextUtils.recycle(buf);
         }
     }
@@ -1200,7 +1200,7 @@
      * Don't call this yourself -- exists for Paint to use internally.
      * {@hide}
      */
-    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
             float[] advances, int advancesPos, Paint p) {
 
         float ret;
@@ -1210,44 +1210,15 @@
 
         if (end <= mGapStart) {
             ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
-                    flags, advances, advancesPos);
+                    advances, advancesPos);
         } else if (start >= mGapStart) {
             ret = p.getTextRunAdvances(mText, start + mGapLength, len,
-                    contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+                    contextStart + mGapLength, contextLen, advances, advancesPos);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunAdvances(buf, start - contextStart, len,
-                    0, contextLen, flags, advances, advancesPos);
-            TextUtils.recycle(buf);
-        }
-
-        return ret;
-    }
-
-    /**
-     * Don't call this yourself -- exists for Paint to use internally.
-     * {@hide}
-     */
-    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
-            float[] advances, int advancesPos, Paint p, int reserved) {
-
-        float ret;
-
-        int contextLen = contextEnd - contextStart;
-        int len = end - start;
-
-        if (end <= mGapStart) {
-            ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
-                    flags, advances, advancesPos, reserved);
-        } else if (start >= mGapStart) {
-            ret = p.getTextRunAdvances(mText, start + mGapLength, len,
-                    contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
-        } else {
-            char[] buf = TextUtils.obtain(contextLen);
-            getChars(contextStart, contextEnd, buf, 0);
-            ret = p.getTextRunAdvances(buf, start - contextStart, len,
-                    0, contextLen, flags, advances, advancesPos, reserved);
+                    0, contextLen, advances, advancesPos);
             TextUtils.recycle(buf);
         }
 
@@ -1270,7 +1241,7 @@
      *
      * @param contextStart the start index of the context
      * @param contextEnd the (non-inclusive) end index of the context
-     * @param flags either DIRECTION_RTL or DIRECTION_LTR
+     * @param flags reserved
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
      * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1281,22 +1252,30 @@
      */
     @Deprecated
     public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
-            int cursorOpt, Paint p) {
+                                int cursorOpt, Paint p) {
+        return getTextRunCursor(contextStart, contextEnd, offset, cursorOpt, p);
+    }
+
+    /**
+     * @hide
+     */
+    public int getTextRunCursor(int contextStart, int contextEnd, int offset,
+                                int cursorOpt, Paint p) {
 
         int ret;
 
         int contextLen = contextEnd - contextStart;
         if (contextEnd <= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart, contextLen,
-                    flags, offset, cursorOpt);
+                    offset, cursorOpt);
         } else if (contextStart >= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
-                    flags, offset + mGapLength, cursorOpt) - mGapLength;
+                    offset + mGapLength, cursorOpt) - mGapLength;
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunCursor(buf, 0, contextLen,
-                    flags, offset - contextStart, cursorOpt) + contextStart;
+                    offset - contextStart, cursorOpt) + contextStart;
             TextUtils.recycle(buf);
         }
 
diff --git a/core/java/android/text/TextDirectionHeuristic.java b/core/java/android/text/TextDirectionHeuristic.java
index 513e11c..8a4ba42 100644
--- a/core/java/android/text/TextDirectionHeuristic.java
+++ b/core/java/android/text/TextDirectionHeuristic.java
@@ -17,10 +17,30 @@
 package android.text;
 
 /**
- * Interface for objects that guess at the paragraph direction by examining text.
- *
- * @hide
+ * Interface for objects that use a heuristic for guessing at the paragraph direction by examining text.
  */
 public interface TextDirectionHeuristic {
-    boolean isRtl(char[] text, int start, int count);
+    /**
+     * Guess if a chars array is in the RTL direction or not.
+     *
+     * @param array the char array.
+     * @param start start index, inclusive.
+     * @param count the length to check, must not be negative and not greater than
+     *          {@code array.length - start}.
+     * @return true if all chars in the range are to be considered in a RTL direction,
+     *          false otherwise.
+     */
+    boolean isRtl(char[] array, int start, int count);
+
+    /**
+     * Guess if a {@code CharSequence} is in the RTL direction or not.
+     *
+     * @param cs the CharSequence.
+     * @param start start index, inclusive.
+     * @param count the length to check, must not be negative and not greater than
+     *            {@code CharSequence.length() - start}.
+     * @return true if all chars in the range are to be considered in a RTL direction,
+     *          false otherwise.
+     */
+    boolean isRtl(CharSequence cs, int start, int count);
 }
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index df8c4c6..7d7e3a9 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -19,43 +19,45 @@
 
 import android.view.View;
 
+import java.nio.CharBuffer;
+
 /**
  * Some objects that implement TextDirectionHeuristic.
  *
- * @hide
  */
 public class TextDirectionHeuristics {
 
-    /** Always decides that the direction is left to right. */
+    /**
+     * Always decides that the direction is left to right.
+     */
     public static final TextDirectionHeuristic LTR =
         new TextDirectionHeuristicInternal(null /* no algorithm */, false);
 
-    /** Always decides that the direction is right to left. */
+    /**
+     * Always decides that the direction is right to left.
+     */
     public static final TextDirectionHeuristic RTL =
         new TextDirectionHeuristicInternal(null /* no algorithm */, true);
 
     /**
-     * Determines the direction based on the first strong directional character,
-     * including bidi format chars, falling back to left to right if it
-     * finds none.  This is the default behavior of the Unicode Bidirectional
-     * Algorithm.
+     * Determines the direction based on the first strong directional character, including bidi
+     * format chars, falling back to left to right if it finds none. This is the default behavior
+     * of the Unicode Bidirectional Algorithm.
      */
     public static final TextDirectionHeuristic FIRSTSTRONG_LTR =
         new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, false);
 
     /**
-     * Determines the direction based on the first strong directional character,
-     * including bidi format chars, falling back to right to left if it
-     * finds none.  This is similar to the default behavior of the Unicode
-     * Bidirectional Algorithm, just with different fallback behavior.
+     * Determines the direction based on the first strong directional character, including bidi
+     * format chars, falling back to right to left if it finds none. This is similar to the default
+     * behavior of the Unicode Bidirectional Algorithm, just with different fallback behavior.
      */
     public static final TextDirectionHeuristic FIRSTSTRONG_RTL =
         new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
 
     /**
-     * If the text contains any strong right to left non-format character, determines
-     * that the direction is right to left, falling back to left to right if it
-     * finds none.
+     * If the text contains any strong right to left non-format character, determines that the
+     * direction is right to left, falling back to left to right if it finds none.
      */
     public static final TextDirectionHeuristic ANYRTL_LTR =
         new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
@@ -65,8 +67,39 @@
      */
     public static final TextDirectionHeuristic LOCALE = TextDirectionHeuristicLocale.INSTANCE;
 
-    private static enum TriState {
-        TRUE, FALSE, UNKNOWN;
+    /**
+     * State constants for taking care about true / false / unknown
+     */
+    private static final int STATE_TRUE = 0;
+    private static final int STATE_FALSE = 1;
+    private static final int STATE_UNKNOWN = 2;
+
+    private static int isRtlText(int directionality) {
+        switch (directionality) {
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+                return STATE_FALSE;
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+                return STATE_TRUE;
+            default:
+                return STATE_UNKNOWN;
+        }
+    }
+
+    private static int isRtlTextOrFormat(int directionality) {
+        switch (directionality) {
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+                return STATE_FALSE;
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+                return STATE_TRUE;
+            default:
+                return STATE_UNKNOWN;
+        }
     }
 
     /**
@@ -87,21 +120,26 @@
         abstract protected boolean defaultIsRtl();
 
         @Override
-        public boolean isRtl(char[] chars, int start, int count) {
-            if (chars == null || start < 0 || count < 0 || chars.length - count < start) {
+        public boolean isRtl(char[] array, int start, int count) {
+            return isRtl(CharBuffer.wrap(array), start, count);
+        }
+
+        @Override
+        public boolean isRtl(CharSequence cs, int start, int count) {
+            if (cs == null || start < 0 || count < 0 || cs.length() - count < start) {
                 throw new IllegalArgumentException();
             }
             if (mAlgorithm == null) {
                 return defaultIsRtl();
             }
-            return doCheck(chars, start, count);
+            return doCheck(cs, start, count);
         }
 
-        private boolean doCheck(char[] chars, int start, int count) {
-            switch(mAlgorithm.checkRtl(chars, start, count)) {
-                case TRUE:
+        private boolean doCheck(CharSequence cs, int start, int count) {
+            switch(mAlgorithm.checkRtl(cs, start, count)) {
+                case STATE_TRUE:
                     return true;
-                case FALSE:
+                case STATE_FALSE:
                     return false;
                 default:
                     return defaultIsRtl();
@@ -124,58 +162,26 @@
         }
     }
 
-    private static TriState isRtlText(int directionality) {
-        switch (directionality) {
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-                return TriState.FALSE;
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-                return TriState.TRUE;
-            default:
-                return TriState.UNKNOWN;
-        }
-    }
-
-    private static TriState isRtlTextOrFormat(int directionality) {
-        switch (directionality) {
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
-                return TriState.FALSE;
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
-                return TriState.TRUE;
-            default:
-                return TriState.UNKNOWN;
-        }
-    }
-
     /**
      * Interface for an algorithm to guess the direction of a paragraph of text.
-     *
      */
     private static interface TextDirectionAlgorithm {
         /**
          * Returns whether the range of text is RTL according to the algorithm.
-         *
          */
-        TriState checkRtl(char[] text, int start, int count);
+        int checkRtl(CharSequence cs, int start, int count);
     }
 
     /**
-     * Algorithm that uses the first strong directional character to determine
-     * the paragraph direction.  This is the standard Unicode Bidirectional
-     * algorithm.
-     *
+     * Algorithm that uses the first strong directional character to determine the paragraph
+     * direction. This is the standard Unicode Bidirectional algorithm.
      */
     private static class FirstStrong implements TextDirectionAlgorithm {
         @Override
-        public TriState checkRtl(char[] text, int start, int count) {
-            TriState result = TriState.UNKNOWN;
-            for (int i = start, e = start + count; i < e && result == TriState.UNKNOWN; ++i) {
-                result = isRtlTextOrFormat(Character.getDirectionality(text[i]));
+        public int checkRtl(CharSequence cs, int start, int count) {
+            int result = STATE_UNKNOWN;
+            for (int i = start, e = start + count; i < e && result == STATE_UNKNOWN; ++i) {
+                result = isRtlTextOrFormat(Character.getDirectionality(cs.charAt(i)));
             }
             return result;
         }
@@ -190,25 +196,24 @@
      * Algorithm that uses the presence of any strong directional non-format
      * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
      * direction of text.
-     *
      */
     private static class AnyStrong implements TextDirectionAlgorithm {
         private final boolean mLookForRtl;
 
         @Override
-        public TriState checkRtl(char[] text, int start, int count) {
+        public int checkRtl(CharSequence cs, int start, int count) {
             boolean haveUnlookedFor = false;
             for (int i = start, e = start + count; i < e; ++i) {
-                switch (isRtlText(Character.getDirectionality(text[i]))) {
-                    case TRUE:
+                switch (isRtlText(Character.getDirectionality(cs.charAt(i)))) {
+                    case STATE_TRUE:
                         if (mLookForRtl) {
-                            return TriState.TRUE;
+                            return STATE_TRUE;
                         }
                         haveUnlookedFor = true;
                         break;
-                    case FALSE:
+                    case STATE_FALSE:
                         if (!mLookForRtl) {
-                            return TriState.FALSE;
+                            return STATE_FALSE;
                         }
                         haveUnlookedFor = true;
                         break;
@@ -217,9 +222,9 @@
                 }
             }
             if (haveUnlookedFor) {
-                return mLookForRtl ? TriState.FALSE : TriState.TRUE;
+                return mLookForRtl ? STATE_FALSE : STATE_TRUE;
             }
-            return TriState.UNKNOWN;
+            return STATE_UNKNOWN;
         }
 
         private AnyStrong(boolean lookForRtl) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1fecf81..e34a0ef 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -664,14 +664,13 @@
             }
         }
 
-        int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
         int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
         if (mCharsValid) {
             return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
-                    flags, offset, cursorOpt);
+                    offset, cursorOpt);
         } else {
             return wp.getTextRunCursor(mText, mStart + spanStart,
-                    mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
+                    mStart + spanLimit, mStart + offset, cursorOpt) - mStart;
         }
     }
 
@@ -738,15 +737,13 @@
 
         int contextLen = contextEnd - contextStart;
         if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
-            int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
-                        contextStart, contextLen, flags, null, 0);
+                        contextStart, contextLen, null, 0);
             } else {
                 int delta = mStart;
-                ret = wp.getTextRunAdvances(mText, delta + start,
-                        delta + end, delta + contextStart, delta + contextEnd,
-                        flags, null, 0);
+                ret = wp.getTextRunAdvances(mText, delta + start, delta + end,
+                        delta + contextStart, delta + contextEnd, null, 0);
             }
         }
 
@@ -786,8 +783,7 @@
                 wp.setAntiAlias(previousAntiAlias);
             }
 
-            drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
-                    x, y + wp.baselineShift);
+            drawTextRun(c, wp, start, end, contextStart, contextEnd, x, y + wp.baselineShift);
         }
 
         return runIsRtl ? -ret : ret;
@@ -970,23 +966,21 @@
      * @param end the end of the run
      * @param contextStart the start of context for the run
      * @param contextEnd the end of the context for the run
-     * @param runIsRtl true if the run is right-to-left
      * @param x the x position of the left edge of the run
      * @param y the baseline of the run
      */
     private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
-            int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
+            int contextStart, int contextEnd, float x, int y) {
 
-        int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
         if (mCharsValid) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start, count, contextStart, contextCount,
-                    x, y, flags, wp);
+                    x, y, wp);
         } else {
             int delta = mStart;
             c.drawTextRun(mText, delta + start, delta + end,
-                    delta + contextStart, delta + contextEnd, x, y, flags, wp);
+                    delta + contextStart, delta + contextEnd, x, y, wp);
         }
     }
 
diff --git a/core/java/android/text/bidi/BidiFormatter.java b/core/java/android/text/bidi/BidiFormatter.java
new file mode 100644
index 0000000..370cbf7
--- /dev/null
+++ b/core/java/android/text/bidi/BidiFormatter.java
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.bidi;
+
+import android.text.TextDirectionHeuristic;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import android.view.View;
+
+import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
+
+import java.util.Locale;
+
+
+/**
+ * Utility class for formatting text for display in a potentially opposite-directionality context
+ * without garbling. The directionality of the context is set at formatter creation and the
+ * directionality of the text can be either estimated or passed in when known. Provides the
+ * following functionality:
+ * <p>
+ * 1. Bidi Wrapping
+ * When text in one language is mixed into a document in another, opposite-directionality language,
+ * e.g. when an English business name is embedded in a Hebrew web page, both the inserted string
+ * and the text surrounding it may be displayed incorrectly unless the inserted string is explicitly
+ * separated from the surrounding text in a "wrapper" that:
+ * <p>
+ * - Declares its directionality so that the string is displayed correctly. This can be done in HTML
+ *   markup (e.g. a 'span dir="rtl"' element) by {@link #spanWrap} and similar methods, or - only in
+ *   contexts where markup can't be used - in Unicode bidi formatting codes by {@link #unicodeWrap}
+ *   and similar methods.
+ * <p>
+ * - Isolates the string's directionality, so it does not unduly affect the surrounding content.
+ *   Currently, this can only be done using invisible Unicode characters of the same direction as
+ *   the context (LRM or RLM) in addition to the directionality declaration above, thus "resetting"
+ *   the directionality to that of the context. The "reset" may need to be done at both ends of the
+ *   string. Without "reset" after the string, the string will "stick" to a number or logically
+ *   separate opposite-direction text that happens to follow it in-line (even if separated by
+ *   neutral content like spaces and punctuation). Without "reset" before the string, the same can
+ *   happen there, but only with more opposite-direction text, not a number. One approach is to
+ *   "reset" the direction only after each string, on the theory that if the preceding opposite-
+ *   direction text is itself bidi-wrapped, the "reset" after it will prevent the sticking. (Doing
+ *   the "reset" only before each string definitely does not work because we do not want to require
+ *   bidi-wrapping numbers, and a bidi-wrapped opposite-direction string could be followed by a
+ *   number.) Still, the safest policy is to do the "reset" on both ends of each string, since RTL
+ *   message translations often contain untranslated Latin-script brand names and technical terms,
+ *   and one of these can be followed by a bidi-wrapped inserted value. On the other hand, when one
+ *   has such a message, it is best to do the "reset" manually in the message translation itself,
+ *   since the message's opposite-direction text could be followed by an inserted number, which we
+ *   would not bidi-wrap anyway. Thus, "reset" only after the string is the current default. In an
+ *   alternative to "reset", recent additions to the HTML, CSS, and Unicode standards allow the
+ *   isolation to be part of the directionality declaration. This form of isolation is better than
+ *   "reset" because it takes less space, does not require knowing the context directionality, has a
+ *   gentler effect than "reset", and protects both ends of the string. However, we do not yet allow
+ *   using it because required platforms do not yet support it.
+ * <p>
+ * Providing these wrapping services is the basic purpose of the bidi formatter.
+ * <p>
+ * 2. Directionality estimation
+ * How does one know whether a string about to be inserted into surrounding text has the same
+ * directionality? Well, in many cases, one knows that this must be the case when writing the code
+ * doing the insertion, e.g. when a localized message is inserted into a localized page. In such
+ * cases there is no need to involve the bidi formatter at all. In some other cases, it need not be
+ * the same as the context, but is either constant (e.g. urls are always LTR) or otherwise known.
+ * In the remaining cases, e.g. when the string is user-entered or comes from a database, the
+ * language of the string (and thus its directionality) is not known a priori, and must be
+ * estimated at run-time. The bidi formatter can do this automatically using the default
+ * first-strong estimation algorithm. It can also be configured to use a custom directionality
+ * estimation object.
+ * <p>
+ * 3. Escaping
+ * When wrapping plain text - i.e. text that is not already HTML or HTML-escaped - in HTML markup,
+ * the text must first be HTML-escaped to prevent XSS attacks and other nasty business. This of
+ * course is always true, but the escaping can not be done after the string has already been wrapped
+ * in markup, so the bidi formatter also serves as a last chance and includes escaping services.
+ * <p>
+ * Thus, in a single call, the formatter will escape the input string as specified, determine its
+ * directionality, and wrap it as necessary. It is then up to the caller to insert the return value
+ * in the output.
+ */
+public final class BidiFormatter {
+
+    /**
+     * The default text direction heuristic.
+     */
+    private static TextDirectionHeuristic DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
+
+    /**
+     * Unicode "Left-To-Right Embedding" (LRE) character.
+     */
+    private static final char LRE = '\u202A';
+
+    /**
+     * Unicode "Right-To-Left Embedding" (RLE) character.
+     */
+    private static final char RLE = '\u202B';
+
+    /**
+     * Unicode "Pop Directional Formatting" (PDF) character.
+     */
+    private static final char PDF = '\u202C';
+
+    /**
+     *  Unicode "Left-To-Right Mark" (LRM) character.
+     */
+    private static final char LRM = '\u200E';
+
+    /*
+     * Unicode "Right-To-Left Mark" (RLM) character.
+     */
+    private static final char RLM = '\u200F';
+
+    /*
+     * String representation of LRM
+     */
+    private static final String LRM_STRING = Character.toString(LRM);
+
+    /*
+     * String representation of RLM
+     */
+    private static final String RLM_STRING = Character.toString(RLM);
+
+    /**
+     * "ltr" string constant.
+     */
+    private static final String LTR_STRING = "ltr";
+
+    /**
+     * "rtl" string constant.
+     */
+    private static final String RTL_STRING = "rtl";
+
+    /**
+     * "dir=\"ltr\"" string constant.
+     */
+    private static final String DIR_LTR_STRING = "dir=\"ltr\"";
+
+    /**
+     * "dir=\"rtl\"" string constant.
+     */
+    private static final String DIR_RTL_STRING = "dir=\"rtl\"";
+
+    /**
+     * "right" string constant.
+     */
+    private static final String RIGHT = "right";
+
+    /**
+     * "left" string constant.
+     */
+    private static final String LEFT = "left";
+
+    /**
+     * Empty string constant.
+     */
+    private static final String EMPTY_STRING = "";
+
+    /**
+     * A class for building a BidiFormatter with non-default options.
+     */
+    public static final class Builder {
+        private boolean isRtlContext;
+        private int flags;
+        private TextDirectionHeuristic textDirectionHeuristic;
+
+        /**
+         * Constructor.
+         *
+         */
+        public Builder() {
+            initialize(isRtlLocale(Locale.getDefault()));
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param rtlContext Whether the context directionality is RTL.
+         */
+        public Builder(boolean rtlContext) {
+            initialize(rtlContext);
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param locale The context locale.
+         */
+        public Builder(Locale locale) {
+            initialize(isRtlLocale(locale));
+        }
+
+        /**
+         * Initializes the builder with the given context directionality and default options.
+         *
+         * @param isRtlContext Whether the context is RTL or not.
+         */
+        private void initialize(boolean isRtlContext) {
+            this.isRtlContext = isRtlContext;
+            textDirectionHeuristic = DEFAULT_TEXT_DIRECTION_HEURISTIC;
+            this.flags = DEFAULT_FLAGS;
+        }
+
+        /**
+         * Specifies whether the BidiFormatter to be built should also "reset" directionality before
+         * a string being bidi-wrapped, not just after it. The default is false.
+         */
+        public Builder stereoReset(boolean stereoReset) {
+            if (stereoReset) {
+                flags |= FLAG_STEREO_RESET;
+            } else {
+                flags &= ~FLAG_STEREO_RESET;
+            }
+            return this;
+        }
+
+        /**
+         * Specifies the default directionality estimation algorithm to be used by the BidiFormatter.
+         * By default, uses the first-strong heuristic.
+         *
+         * @param heuristic the {@code TextDirectionHeuristic} to use.
+         * @return the builder itself.
+         */
+        public Builder setTextDirectionHeuristic(TextDirectionHeuristic heuristic) {
+            this.textDirectionHeuristic = heuristic;
+            return this;
+        }
+
+        private static BidiFormatter getDefaultInstanceFromContext(boolean isRtlContext) {
+            return isRtlContext ? DEFAULT_RTL_INSTANCE : DEFAULT_LTR_INSTANCE;
+        }
+
+        /**
+         * @return A BidiFormatter with the specified options.
+         */
+        public BidiFormatter build() {
+            if (flags == DEFAULT_FLAGS &&
+                    textDirectionHeuristic == DEFAULT_TEXT_DIRECTION_HEURISTIC) {
+                return getDefaultInstanceFromContext(isRtlContext);
+            }
+            return new BidiFormatter(isRtlContext, flags, textDirectionHeuristic);
+        }
+    }
+
+    //
+    private static final int FLAG_STEREO_RESET = 2;
+    private static final int DEFAULT_FLAGS = FLAG_STEREO_RESET;
+
+    private static final BidiFormatter DEFAULT_LTR_INSTANCE = new BidiFormatter(
+            false /* LTR context */,
+            DEFAULT_FLAGS,
+            DEFAULT_TEXT_DIRECTION_HEURISTIC);
+
+    private static final BidiFormatter DEFAULT_RTL_INSTANCE = new BidiFormatter(
+            true /* RTL context */,
+            DEFAULT_FLAGS,
+            DEFAULT_TEXT_DIRECTION_HEURISTIC);
+
+    private final boolean isRtlContext;
+    private final int flags;
+    private final TextDirectionHeuristic defaultTextDirectionHeuristic;
+
+    /**
+     * Factory for creating an instance of BidiFormatter given the context directionality.
+     *
+     * @param rtlContext Whether the context directionality is RTL.
+     */
+    public static BidiFormatter getInstance(boolean rtlContext) {
+        return new Builder(rtlContext).build();
+    }
+
+    /**
+     * Factory for creating an instance of BidiFormatter given the context locale.
+     *
+     * @param locale The context locale.
+     */
+    public static BidiFormatter getInstance(Locale locale) {
+        return new Builder(locale).build();
+    }
+
+    /**
+     * @param isRtlContext Whether the context directionality is RTL or not.
+     * @param flags The option flags.
+     * @param heuristic The default text direction heuristic.
+     */
+    private BidiFormatter(boolean isRtlContext, int flags, TextDirectionHeuristic heuristic) {
+        this.isRtlContext = isRtlContext;
+        this.flags = flags;
+        this.defaultTextDirectionHeuristic = heuristic;
+    }
+
+    /**
+     * @return Whether the context directionality is RTL
+     */
+    public boolean isRtlContext() {
+        return isRtlContext;
+    }
+
+    /**
+     * @return Whether directionality "reset" should also be done before a string being
+     * bidi-wrapped, not just after it.
+     */
+    public boolean getStereoReset() {
+        return (flags & FLAG_STEREO_RESET) != 0;
+    }
+
+    /**
+     * Returns "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" if it is LTR.
+     *
+     * @param str String whose directionality is to be estimated.
+     * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
+     */
+    public String dirAttrValue(String str) {
+        return dirAttrValue(isRtl(str));
+    }
+
+    /**
+     * Operates like {@link #dirAttrValue(String)}, but uses a given heuristic to estimate the
+     * {@code str}'s directionality.
+     *
+     * @param str String whose directionality is to be estimated.
+     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+     *                  directionality.
+     * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
+     */
+    public String dirAttrValue(String str, TextDirectionHeuristic heuristic) {
+        return dirAttrValue(heuristic.isRtl(str, 0, str.length()));
+    }
+
+    /**
+     * Returns "rtl" if the given directionality is RTL, and "ltr" if it is LTR.
+     *
+     * @param isRtl Whether the directionality is RTL or not.
+     * @return "rtl" if the given directionality is RTL, and "ltr" otherwise.
+     */
+    public String dirAttrValue(boolean isRtl) {
+        return isRtl ? RTL_STRING : LTR_STRING;
+    }
+
+    /**
+     * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on {@code str}'s estimated directionality,
+     * if it is not the same as the context directionality. Otherwise, returns the empty string.
+     *
+     * @param str String whose directionality is to be estimated.
+     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+     *     context; else, the empty string.
+     */
+    public String dirAttr(String str) {
+        return dirAttr(isRtl(str));
+    }
+
+    /**
+     * Operates like {@link #dirAttr(String)}, but uses a given heuristic to estimate the
+     * {@code str}'s directionality.
+     *
+     * @param str String whose directionality is to be estimated.
+     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+     *                  directionality.
+     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+     *     context; else, the empty string.
+     */
+    public String dirAttr(String str, TextDirectionHeuristic heuristic) {
+        return dirAttr(heuristic.isRtl(str, 0, str.length()));
+    }
+
+    /**
+     * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on the given directionality, if it is not
+     * the same as the context directionality. Otherwise, returns the empty string.
+     *
+     * @param isRtl Whether the directionality is RTL or not
+     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
+     *     context; else, the empty string.
+     */
+    public String dirAttr(boolean isRtl) {
+        return (isRtl != isRtlContext) ? (isRtl ? DIR_RTL_STRING :  DIR_LTR_STRING) : EMPTY_STRING;
+    }
+
+    /**
+     * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
+     * overall or the exit directionality of a given string is opposite to the context directionality.
+     * Putting this after the string (including its directionality declaration wrapping) prevents it
+     * from "sticking" to other opposite-directionality text or a number appearing after it inline
+     * with only neutral content in between. Otherwise returns the empty string. While the exit
+     * directionality is determined by scanning the end of the string, the overall directionality is
+     * given explicitly in {@code dir}.
+     *
+     * @param str String after which the mark may need to appear.
+     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+     *     else, the empty string.
+     */
+    public String markAfter(String str) {
+        return markAfter(str, defaultTextDirectionHeuristic);
+    }
+
+    /**
+     * Operates like {@link #markAfter(String)}, but uses a given heuristic to estimate the
+     * {@code str}'s directionality.
+     *
+     * @param str String after which the mark may need to appear.
+     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+     *                  directionality.
+     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+     *     else, the empty string.
+     */
+    public String markAfter(String str, TextDirectionHeuristic heuristic) {
+        final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+        // getExitDir() is called only if needed (short-circuit).
+        if (!isRtlContext && (isRtl || getExitDir(str) == DIR_RTL)) {
+            return LRM_STRING;
+        }
+        if (isRtlContext && (!isRtl || getExitDir(str) == DIR_LTR)) {
+            return RLM_STRING;
+        }
+        return EMPTY_STRING;
+    }
+
+    /**
+     * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
+     * overall or the entry directionality of a given string is opposite to the context
+     * directionality. Putting this before the string (including its directionality declaration
+     * wrapping) prevents it from "sticking" to other opposite-directionality text appearing before it
+     * inline with only neutral content in between. Otherwise returns the empty string. While the
+     * entry directionality is determined by scanning the beginning of the string, the overall
+     * directionality is given explicitly in {@code dir}.
+     *
+     * @param str String before which the mark may need to appear.
+     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+     *     else, the empty string.
+     */
+    public String markBefore(String str) {
+        return markBefore(str, defaultTextDirectionHeuristic);
+    }
+
+    /**
+     * Operates like {@link #markBefore(String)}, but uses a given heuristic to estimate the
+     * {@code str}'s directionality.
+     *
+     * @param str String before which the mark may need to appear.
+     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
+     *                  directionality.
+     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
+     *     else, the empty string.
+     */
+    public String markBefore(String str, TextDirectionHeuristic heuristic) {
+        final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+        // getEntryDir() is called only if needed (short-circuit).
+        if (!isRtlContext && (isRtl || getEntryDir(str) == DIR_RTL)) {
+            return LRM_STRING;
+        }
+        if (isRtlContext && (!isRtl || getEntryDir(str) == DIR_LTR)) {
+            return RLM_STRING;
+        }
+        return EMPTY_STRING;
+    }
+
+    /**
+     * Returns the Unicode bidi mark matching the context directionality (LRM for LTR context
+     * directionality, RLM for RTL context directionality).
+     */
+    public String mark() {
+        return isRtlContext ? RLM_STRING : LRM_STRING;
+    }
+
+    /**
+     * Returns "right" for RTL context directionality. Otherwise for LTR context directionality
+     * returns "left".
+     */
+    public String startEdge() {
+        return isRtlContext  ? RIGHT : LEFT;
+    }
+
+    /**
+     * Returns "left" for RTL context directionality. Otherwise for LTR context directionality
+     * returns "right".
+     */
+    public String endEdge() {
+        return isRtlContext ? LEFT : RIGHT;
+    }
+
+    /**
+     * Estimates the directionality of a string using the default text direction heuristic.
+     *
+     * @param str String whose directionality is to be estimated.
+     * @return true if {@code str}'s estimated overall directionality is RTL. Otherwise returns
+     *          false.
+     */
+    public boolean isRtl(String str) {
+        return defaultTextDirectionHeuristic.isRtl(str, 0, str.length());
+    }
+
+    /**
+     * Formats a given string of unknown directionality for use in HTML output of the context
+     * directionality, so an opposite-directionality string is neither garbled nor garbles its
+     * surroundings.
+     * <p>
+     * The algorithm: estimates the directionality of the given string using the given heuristic.
+     * If the directionality is known, pass TextDirectionHeuristics.LTR or RTL for heuristic.
+     * In case its directionality doesn't match the context directionality, wraps it with a 'span'
+     * element and adds a "dir" attribute (either 'dir=\"rtl\"' or 'dir=\"ltr\"').
+     * <p>
+     * If {@code isolate}, directionally isolates the string so that it does not garble its
+     * surroundings. Currently, this is done by "resetting" the directionality after the string by
+     * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
+     * either the overall directionality or the exit directionality of the string is opposite to that
+     * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
+     * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
+     * directionality when either the overall directionality or the entry directionality of the
+     * string is opposite to that of the context.
+     * <p>
+     *
+     * @param str The input string.
+     * @param heuristic The algorithm to be used to estimate the string's overall direction.
+     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+     *     content around it.
+     * @return Input string after applying the above processing.
+     */
+    public String spanWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+        final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+        String origStr = str;
+        str = TextUtils.htmlEncode(str);
+
+        StringBuilder result = new StringBuilder();
+        if (getStereoReset() && isolate) {
+            result.append(markBefore(origStr,
+                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+        }
+        if (isRtl != isRtlContext) {
+            result.append("<span ").append(dirAttr(isRtl)).append('>').append(str).append("</span>");
+        } else {
+            result.append(str);
+        }
+        if (isolate) {
+            result.append(markAfter(origStr,
+                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but assumes
+     * {@code isolate} is true.
+     *
+     * @param str The input string.
+     * @param heuristic The algorithm to be used to estimate the string's overall direction.
+     * @return Input string after applying the above processing.
+     */
+    public String spanWrap(String str, TextDirectionHeuristic heuristic) {
+        return spanWrap(str, heuristic, true /* isolate */);
+    }
+
+    /**
+     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+     * formatter's default direction estimation algorithm.
+     *
+     * @param str The input string.
+     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+     *     content around it
+     * @return Input string after applying the above processing.
+     */
+    public String spanWrap(String str, boolean isolate) {
+        return spanWrap(str, defaultTextDirectionHeuristic, isolate);
+    }
+
+    /**
+     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+     * formatter's default direction estimation algorithm and assumes {@code isolate} is true.
+     *
+     * @param str The input string.
+     * @return Input string after applying the above processing.
+     */
+    public String spanWrap(String str) {
+        return spanWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+    }
+
+    /**
+     * Formats a string of given directionality for use in plain-text output of the context
+     * directionality, so an opposite-directionality string is neither garbled nor garbles its
+     * surroundings. As opposed to {@link #spanWrap}, this makes use of Unicode bidi
+     * formatting characters. In HTML, its *only* valid use is inside of elements that do not allow
+     * markup, e.g. the 'option' and 'title' elements.
+     * <p>
+     * The algorithm: In case the given directionality doesn't match the context directionality, wraps
+     * the string with Unicode bidi formatting characters: RLE+{@code str}+PDF for RTL text, or
+     * LRE+{@code str}+PDF for LTR text.
+     * <p>
+     * If {@code isolate}, directionally isolates the string so that it does not garble its
+     * surroundings. Currently, this is done by "resetting" the directionality after the string by
+     * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
+     * either the overall directionality or the exit directionality of the string is opposite to that
+     * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
+     * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
+     * directionality when either the overall directionality or the entry directionality of the
+     * string is opposite to that of the context. Note that as opposed to the overall
+     * directionality, the entry and exit directionalities are determined from the string itself.
+     * <p>
+     * Does *not* do HTML-escaping.
+     *
+     * @param str The input string.
+     * @param heuristic The algorithm to be used to estimate the string's overall direction.
+     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+     *     content around it
+     * @return Input string after applying the above processing.
+     */
+    public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+        final boolean isRtl = heuristic.isRtl(str, 0, str.length());
+        StringBuilder result = new StringBuilder();
+        if (getStereoReset() && isolate) {
+            result.append(markBefore(str,
+                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+        }
+        if (isRtl != isRtlContext) {
+            result.append(isRtl ? RLE : LRE);
+            result.append(str);
+            result.append(PDF);
+        } else {
+            result.append(str);
+        }
+        if (isolate) {
+            result.append(markAfter(str,
+                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but assumes
+     * {@code isolate} is true.
+     *
+     * @param str The input string.
+     * @param heuristic The algorithm to be used to estimate the string's overall direction.
+     * @return Input string after applying the above processing.
+     */
+    public String unicodeWrap(String str, TextDirectionHeuristic heuristic) {
+        return unicodeWrap(str, heuristic, true /* isolate */);
+    }
+
+    /**
+     * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+     * formatter's default direction estimation algorithm.
+     *
+     * @param str The input string.
+     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
+     *     content around it
+     * @return Input string after applying the above processing.
+     */
+    public String unicodeWrap(String str, boolean isolate) {
+        return unicodeWrap(str, defaultTextDirectionHeuristic, isolate);
+    }
+
+    /**
+     * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the
+     * formatter's default direction estimation algorithm and assumes {@code isolate} is true.
+     *
+     * @param str The input string.
+     * @return Input string after applying the above processing.
+     */
+    public String unicodeWrap(String str) {
+        return unicodeWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+    }
+
+    /**
+     * Helper method to return true if the Locale directionality is RTL.
+     *
+     * @param locale The Locale whose directionality will be checked to be RTL or LTR
+     * @return true if the {@code locale} directionality is RTL. False otherwise.
+     */
+    private static boolean isRtlLocale(Locale locale) {
+        return (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL);
+    }
+
+    /**
+     * Enum for directionality type.
+     */
+    private static final int DIR_LTR = -1;
+    private static final int DIR_UNKNOWN = 0;
+    private static final int DIR_RTL = +1;
+
+    /**
+     * Returns the directionality of the last character with strong directionality in the string, or
+     * DIR_UNKNOWN if none was encountered. For efficiency, actually scans backwards from the end of
+     * the string. Treats a non-BN character between an LRE/RLE/LRO/RLO and its matching PDF as a
+     * strong character, LTR after LRE/LRO, and RTL after RLE/RLO. The results are undefined for a
+     * string containing unbalanced LRE/RLE/LRO/RLO/PDF characters. The intended use is to check
+     * whether a logically separate item that starts with a number or a character of the string's
+     * exit directionality and follows this string inline (not counting any neutral characters in
+     * between) would "stick" to it in an opposite-directionality context, thus being displayed in
+     * an incorrect position. An LRM or RLM character (the one of the context's directionality)
+     * between the two will prevent such sticking.
+     *
+     * @param str the string to check.
+     */
+    private static int getExitDir(String str) {
+        return new DirectionalityEstimator(str, false /* isHtml */).getExitDir();
+    }
+
+    /**
+     * Returns the directionality of the first character with strong directionality in the string,
+     * or DIR_UNKNOWN if none was encountered. Treats a non-BN character between an
+     * LRE/RLE/LRO/RLO and its matching PDF as a strong character, LTR after LRE/LRO, and RTL after
+     * RLE/RLO. The results are undefined for a string containing unbalanced LRE/RLE/LRO/RLO/PDF
+     * characters. The intended use is to check whether a logically separate item that ends with a
+     * character of the string's entry directionality and precedes the string inline (not counting
+     * any neutral characters in between) would "stick" to it in an opposite-directionality context,
+     * thus being displayed in an incorrect position. An LRM or RLM character (the one of the
+     * context's directionality) between the two will prevent such sticking.
+     *
+     * @param str the string to check.
+     */
+    private static int getEntryDir(String str) {
+        return new DirectionalityEstimator(str, false /* isHtml */).getEntryDir();
+    }
+
+    /**
+     * An object that estimates the directionality of a given string by various methods.
+     *
+     */
+    private static class DirectionalityEstimator {
+
+        // Internal static variables and constants.
+
+        /**
+         * Size of the bidi character class cache. The results of the Character.getDirectionality()
+         * calls on the lowest DIR_TYPE_CACHE_SIZE codepoints are kept in an array for speed.
+         * The 0x700 value is designed to leave all the European and Near Eastern languages in the
+         * cache. It can be reduced to 0x180, restricting the cache to the Western European
+         * languages.
+         */
+        private static final int DIR_TYPE_CACHE_SIZE = 0x700;
+
+        /**
+         * The bidi character class cache.
+         */
+        private static final byte DIR_TYPE_CACHE[];
+
+        static {
+            DIR_TYPE_CACHE = new byte[DIR_TYPE_CACHE_SIZE];
+            for (int i = 0; i < DIR_TYPE_CACHE_SIZE; i++) {
+                DIR_TYPE_CACHE[i] = Character.getDirectionality(i);
+            }
+        }
+
+        // Internal instance variables.
+
+        /**
+         * The text to be scanned.
+         */
+        private final String text;
+
+        /**
+         * Whether the text to be scanned is to be treated as HTML, i.e. skipping over tags and
+         * entities when looking for the next / preceding dir type.
+         */
+        private final boolean isHtml;
+
+        /**
+         * The length of the text in chars.
+         */
+        private final int length;
+
+        /**
+         * The current position in the text.
+         */
+        private int charIndex;
+
+        /**
+         * The char encountered by the last dirTypeForward or dirTypeBackward call. If it
+         * encountered a supplementary codepoint, this contains a char that is not a valid
+         * codepoint. This is ok, because this member is only used to detect some well-known ASCII
+         * syntax, e.g. "http://" and the beginning of an HTML tag or entity.
+         */
+        private char lastChar;
+
+        /**
+         * Constructor.
+         *
+         * @param text The string to scan.
+         * @param isHtml Whether the text to be scanned is to be treated as HTML, i.e. skipping over
+         *     tags and entities.
+         */
+        DirectionalityEstimator(String text, boolean isHtml) {
+            this.text = text;
+            this.isHtml = isHtml;
+            length = text.length();
+        }
+
+        /**
+         * Returns the directionality of the first character with strong directionality in the
+         * string, or DIR_UNKNOWN if none was encountered. Treats a non-BN character between an
+         * LRE/RLE/LRO/RLO and its matching PDF as a strong character, LTR after LRE/LRO, and RTL
+         * after RLE/RLO. The results are undefined for a string containing unbalanced
+         * LRE/RLE/LRO/RLO/PDF characters.
+         */
+        int getEntryDir() {
+            // The reason for this method name, as opposed to getFirstStrongDir(), is that
+            // "first strong" is a commonly used description of Unicode's estimation algorithm,
+            // but the two must treat formatting characters quite differently. Thus, we are staying
+            // away from both "first" and "last" in these method names to avoid confusion.
+            charIndex = 0;
+            int embeddingLevel = 0;
+            int embeddingLevelDir = DIR_UNKNOWN;
+            int firstNonEmptyEmbeddingLevel = 0;
+            while (charIndex < length && firstNonEmptyEmbeddingLevel == 0) {
+                switch (dirTypeForward()) {
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+                        ++embeddingLevel;
+                        embeddingLevelDir = DIR_LTR;
+                        break;
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+                        ++embeddingLevel;
+                        embeddingLevelDir = DIR_RTL;
+                        break;
+                    case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+                        --embeddingLevel;
+                        // To restore embeddingLevelDir to its previous value, we would need a
+                        // stack, which we want to avoid. Thus, at this point we do not know the
+                        // current embedding's directionality.
+                        embeddingLevelDir = DIR_UNKNOWN;
+                        break;
+                    case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL:
+                        break;
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+                        if (embeddingLevel == 0) {
+                            return DIR_LTR;
+                        }
+                        firstNonEmptyEmbeddingLevel = embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+                        if (embeddingLevel == 0) {
+                            return DIR_RTL;
+                        }
+                        firstNonEmptyEmbeddingLevel = embeddingLevel;
+                        break;
+                    default:
+                        firstNonEmptyEmbeddingLevel = embeddingLevel;
+                        break;
+                }
+            }
+
+            // We have either found a non-empty embedding or scanned the entire string finding
+            // neither a non-empty embedding nor a strong character outside of an embedding.
+            if (firstNonEmptyEmbeddingLevel == 0) {
+                // We have not found a non-empty embedding. Thus, the string contains neither a
+                // non-empty embedding nor a strong character outside of an embedding.
+                return DIR_UNKNOWN;
+            }
+
+            // We have found a non-empty embedding.
+            if (embeddingLevelDir != DIR_UNKNOWN) {
+                // We know the directionality of the non-empty embedding.
+                return embeddingLevelDir;
+            }
+
+            // We do not remember the directionality of the non-empty embedding we found. So, we go
+            // backwards to find the start of the non-empty embedding and get its directionality.
+            while (charIndex > 0) {
+                switch (dirTypeBackward()) {
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+                        if (firstNonEmptyEmbeddingLevel == embeddingLevel) {
+                            return DIR_LTR;
+                        }
+                        --embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+                        if (firstNonEmptyEmbeddingLevel == embeddingLevel) {
+                            return DIR_RTL;
+                        }
+                        --embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+                        ++embeddingLevel;
+                        break;
+                }
+            }
+            // We should never get here.
+            return DIR_UNKNOWN;
+        }
+
+        /**
+         * Returns the directionality of the last character with strong directionality in the
+         * string, or DIR_UNKNOWN if none was encountered. For efficiency, actually scans backwards
+         * from the end of the string. Treats a non-BN character between an LRE/RLE/LRO/RLO and its
+         * matching PDF as a strong character, LTR after LRE/LRO, and RTL after RLE/RLO. The results
+         * are undefined for a string containing unbalanced LRE/RLE/LRO/RLO/PDF characters.
+         */
+        int getExitDir() {
+            // The reason for this method name, as opposed to getLastStrongDir(), is that "last
+            // strong" sounds like the exact opposite of "first strong", which is a commonly used
+            // description of Unicode's estimation algorithm (getUnicodeDir() above), but the two
+            // must treat formatting characters quite differently. Thus, we are staying away from
+            // both "first" and "last" in these method names to avoid confusion.
+            charIndex = length;
+            int embeddingLevel = 0;
+            int lastNonEmptyEmbeddingLevel = 0;
+            while (charIndex > 0) {
+                switch (dirTypeBackward()) {
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+                        if (embeddingLevel == 0) {
+                            return DIR_LTR;
+                        }
+                        if (lastNonEmptyEmbeddingLevel == 0) {
+                            lastNonEmptyEmbeddingLevel = embeddingLevel;
+                        }
+                        break;
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+                    case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+                        if (lastNonEmptyEmbeddingLevel == embeddingLevel) {
+                            return DIR_LTR;
+                        }
+                        --embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+                        if (embeddingLevel == 0) {
+                            return DIR_RTL;
+                        }
+                        if (lastNonEmptyEmbeddingLevel == 0) {
+                            lastNonEmptyEmbeddingLevel = embeddingLevel;
+                        }
+                        break;
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+                    case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+                        if (lastNonEmptyEmbeddingLevel == embeddingLevel) {
+                            return DIR_RTL;
+                        }
+                        --embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
+                        ++embeddingLevel;
+                        break;
+                    case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL:
+                        break;
+                    default:
+                        if (lastNonEmptyEmbeddingLevel == 0) {
+                            lastNonEmptyEmbeddingLevel = embeddingLevel;
+                        }
+                        break;
+                }
+            }
+            return DIR_UNKNOWN;
+        }
+
+        // Internal methods
+
+        /**
+         * Gets the bidi character class, i.e. Character.getDirectionality(), of a given char, using
+         * a cache for speed. Not designed for supplementary codepoints, whose results we do not
+         * cache.
+         */
+        private static byte getCachedDirectionality(char c) {
+            return c < DIR_TYPE_CACHE_SIZE ? DIR_TYPE_CACHE[c] : Character.getDirectionality(c);
+        }
+
+        /**
+         * Returns the Character.DIRECTIONALITY_... value of the next codepoint and advances
+         * charIndex. If isHtml, and the codepoint is '<' or '&', advances through the tag/entity,
+         * and returns Character.DIRECTIONALITY_WHITESPACE. For an entity, it would be best to
+         * figure out the actual character, and return its dirtype, but treating it as whitespace is
+         * good enough for our purposes.
+         *
+         * @throws java.lang.IndexOutOfBoundsException if called when charIndex >= length or < 0.
+         */
+        byte dirTypeForward() {
+            lastChar = text.charAt(charIndex);
+            if (Character.isHighSurrogate(lastChar)) {
+                int codePoint = Character.codePointAt(text, charIndex);
+                charIndex += Character.charCount(codePoint);
+                return Character.getDirectionality(codePoint);
+            }
+            charIndex++;
+            byte dirType = getCachedDirectionality(lastChar);
+            if (isHtml) {
+                // Process tags and entities.
+                if (lastChar == '<') {
+                    dirType = skipTagForward();
+                } else if (lastChar == '&') {
+                    dirType = skipEntityForward();
+                }
+            }
+            return dirType;
+        }
+
+        /**
+         * Returns the Character.DIRECTIONALITY_... value of the preceding codepoint and advances
+         * charIndex backwards. If isHtml, and the codepoint is the end of a complete HTML tag or
+         * entity, advances over the whole tag/entity and returns
+         * Character.DIRECTIONALITY_WHITESPACE. For an entity, it would be best to figure out the
+         * actual character, and return its dirtype, but treating it as whitespace is good enough
+         * for our purposes.
+         *
+         * @throws java.lang.IndexOutOfBoundsException if called when charIndex > length or <= 0.
+         */
+        byte dirTypeBackward() {
+            lastChar = text.charAt(charIndex - 1);
+            if (Character.isLowSurrogate(lastChar)) {
+                int codePoint = Character.codePointBefore(text, charIndex);
+                charIndex -= Character.charCount(codePoint);
+                return Character.getDirectionality(codePoint);
+            }
+            charIndex--;
+            byte dirType = getCachedDirectionality(lastChar);
+            if (isHtml) {
+                // Process tags and entities.
+                if (lastChar == '>') {
+                    dirType = skipTagBackward();
+                } else if (lastChar == ';') {
+                    dirType = skipEntityBackward();
+                }
+            }
+            return dirType;
+        }
+
+        /**
+         * Advances charIndex forward through an HTML tag (after the opening &lt; has already been
+         * read) and returns Character.DIRECTIONALITY_WHITESPACE. If there is no matching &gt;,
+         * does not change charIndex and returns Character.DIRECTIONALITY_OTHER_NEUTRALS (for the
+         * &lt; that hadn't been part of a tag after all).
+         */
+        private byte skipTagForward() {
+            int initialCharIndex = charIndex;
+            while (charIndex < length) {
+                lastChar = text.charAt(charIndex++);
+                if (lastChar == '>') {
+                    // The end of the tag.
+                    return Character.DIRECTIONALITY_WHITESPACE;
+                }
+                if (lastChar == '"' || lastChar == '\'') {
+                    // Skip over a quoted attribute value inside the tag.
+                    char quote = lastChar;
+                    while (charIndex < length && (lastChar = text.charAt(charIndex++)) != quote) {}
+                }
+            }
+            // The original '<' wasn't the start of a tag after all.
+            charIndex = initialCharIndex;
+            lastChar = '<';
+            return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+        }
+
+        /**
+         * Advances charIndex backward through an HTML tag (after the closing &gt; has already been
+         * read) and returns Character.DIRECTIONALITY_WHITESPACE. If there is no matching &lt;, does
+         * not change charIndex and returns Character.DIRECTIONALITY_OTHER_NEUTRALS (for the &gt;
+         * that hadn't been part of a tag after all). Nevertheless, the running time for calling
+         * skipTagBackward() in a loop remains linear in the size of the text, even for a text like
+         * "&gt;&gt;&gt;&gt;", because skipTagBackward() also stops looking for a matching &lt;
+         * when it encounters another &gt;.
+         */
+        private byte skipTagBackward() {
+            int initialCharIndex = charIndex;
+            while (charIndex > 0) {
+                lastChar = text.charAt(--charIndex);
+                if (lastChar == '<') {
+                    // The start of the tag.
+                    return Character.DIRECTIONALITY_WHITESPACE;
+                }
+                if (lastChar == '>') {
+                    break;
+                }
+                if (lastChar == '"' || lastChar == '\'') {
+                    // Skip over a quoted attribute value inside the tag.
+                    char quote = lastChar;
+                    while (charIndex > 0 && (lastChar = text.charAt(--charIndex)) != quote) {}
+                }
+            }
+            // The original '>' wasn't the end of a tag after all.
+            charIndex = initialCharIndex;
+            lastChar = '>';
+            return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+        }
+
+        /**
+         * Advances charIndex forward through an HTML character entity tag (after the opening
+         * &amp; has already been read) and returns Character.DIRECTIONALITY_WHITESPACE. It would be
+         * best to figure out the actual character and return its dirtype, but this is good enough.
+         */
+        private byte skipEntityForward() {
+            while (charIndex < length && (lastChar = text.charAt(charIndex++)) != ';') {}
+            return Character.DIRECTIONALITY_WHITESPACE;
+        }
+
+        /**
+         * Advances charIndex backward through an HTML character entity tag (after the closing ;
+         * has already been read) and returns Character.DIRECTIONALITY_WHITESPACE. It would be best
+         * to figure out the actual character and return its dirtype, but this is good enough.
+         * If there is no matching &amp;, does not change charIndex and returns
+         * Character.DIRECTIONALITY_OTHER_NEUTRALS (for the ';' that did not start an entity after
+         * all). Nevertheless, the running time for calling skipEntityBackward() in a loop remains
+         * linear in the size of the text, even for a text like ";;;;;;;", because skipTagBackward()
+         * also stops looking for a matching &amp; when it encounters another ;.
+         */
+        private byte skipEntityBackward() {
+            int initialCharIndex = charIndex;
+            while (charIndex > 0) {
+                lastChar = text.charAt(--charIndex);
+                if (lastChar == '&') {
+                    return Character.DIRECTIONALITY_WHITESPACE;
+                }
+                if (lastChar == ';') {
+                    break;
+                }
+            }
+            charIndex = initialCharIndex;
+            lastChar = ';';
+            return Character.DIRECTIONALITY_OTHER_NEUTRALS;
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index e856501..dae47b8 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -74,6 +74,15 @@
     public static final int DENSITY_XXHIGH = 480;
 
     /**
+     * Standard quantized DPI for extra-extra-extra-high-density screens.  Applications
+     * should not generally worry about this density; relying on XHIGH graphics
+     * being scaled up to it should be sufficient for almost all cases.  A typical
+     * use of this density would be 4K television screens -- 3840x2160, which
+     * is 2x a traditional HD 1920x1080 screen which runs at DENSITY_XHIGH.
+     */
+    public static final int DENSITY_XXXHIGH = 640;
+
+    /**
      * The reference density used throughout the system.
      */
     public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 81c25d8..2d6453e 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import android.app.ActivityThread;
-import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -218,13 +216,8 @@
                 root = mViewRootImpl.mView;
             }
             if (root != null) {
-                int resolvedViewId = root.getContext().getResources().getIdentifier(
-                        viewId, "id", root.getContext().getPackageName());
-                if (resolvedViewId <= 0) {
-                    resolvedViewId = ((Context) ActivityThread.currentActivityThread()
-                            .getSystemContext()).getResources()
-                            .getIdentifier(viewId, "id", "android");
-                }
+                final int resolvedViewId = root.getContext().getResources()
+                        .getIdentifier(viewId, null, null);
                 if (resolvedViewId <= 0) {
                     return;
                 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 80c9324..ec7c65a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1176,14 +1176,14 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
+            nDrawText(mRenderer, text, index, count, x, y, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
     
     private static native void nDrawText(int renderer, char[] text, int index, int count,
-            float x, float y, int bidiFlags, int paint);
+            float x, float y, int paint);
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@@ -1191,16 +1191,14 @@
         try {
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
-                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
-                        paint.mNativePaint);
+                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mNativePaint);
             } else if (text instanceof GraphicsOperations) {
                 ((GraphicsOperations) text).drawText(this, start, end, x, y,
                                                          paint);
             } else {
                 char[] buf = TemporaryBuffer.obtain(end - start);
                 TextUtils.getChars(text, start, end, buf, 0);
-                nDrawText(mRenderer, buf, 0, end - start, x, y,
-                        paint.mBidiFlags, paint.mNativePaint);
+                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1216,21 +1214,20 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
+            nDrawText(mRenderer, text, start, end, x, y, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawText(int renderer, String text, int start, int end,
-            float x, float y, int bidiFlags, int paint);
+            float x, float y, int paint);
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
-                    paint.mNativePaint);
+            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
@@ -1246,14 +1243,14 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
-            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
+            int path, float hOffset, float vOffset, int nativePaint);
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
@@ -1262,28 +1259,25 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
-            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
+            int path, float hOffset, float vOffset, int nativePaint);
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, Paint paint) {
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
-            throw new IllegalArgumentException("Unknown direction: " + dir);
-        }
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
+            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y,
                     paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
@@ -1291,32 +1285,31 @@
     }
 
     private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
-            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
+            int contextIndex, int contextCount, float x, float y, int nativePaint);
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, Paint paint) {
         if ((start | end | end - start | text.length() - end) < 0) {
             throw new IndexOutOfBoundsException();
         }
 
         int modifiers = setupModifiers(paint);
         try {
-            int flags = dir == 0 ? 0 : 1;
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
                 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                        contextEnd, x, y, flags, paint.mNativePaint);
+                        contextEnd, x, y, paint.mNativePaint);
             } else if (text instanceof GraphicsOperations) {
                 ((GraphicsOperations) text).drawTextRun(this, start, end,
-                        contextStart, contextEnd, x, y, flags, paint);
+                        contextStart, contextEnd, x, y, paint);
             } else {
                 int contextLen = contextEnd - contextStart;
                 int len = end - start;
                 char[] buf = TemporaryBuffer.obtain(contextLen);
                 TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
                 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
-                        x, y, flags, paint.mNativePaint);
+                        x, y, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1325,7 +1318,7 @@
     }
 
     private static native void nDrawTextRun(int renderer, String text, int start, int end,
-            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
+            int contextStart, int contextEnd, float x, float y, int nativePaint);
 
     @Override
     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 7da2451..947cf44 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -267,15 +267,15 @@
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, int dir, Paint paint) {
-        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
+            float x, float y, Paint paint) {
+        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, paint);
         recordShaderBitmap(paint);
     }
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart,
-            int contextEnd, float x, float y, int dir, Paint paint) {
-        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
+            int contextEnd, float x, float y, Paint paint) {
+        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, paint);
         recordShaderBitmap(paint);
     }
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e0d48a4..7c4bcfd 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -48,7 +48,7 @@
 import static javax.microedition.khronos.egl.EGL10.*;
 
 /**
- * Interface for rendering a ViewAncestor using hardware acceleration.
+ * Interface for rendering a view hierarchy using hardware acceleration.
  * 
  * @hide
  */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c3eae3a..25cad87 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1868,6 +1868,12 @@
     private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
 
     /**
+     * Default horizontal layout direction.
+     * @hide
+     */
+    static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR;
+
+    /**
      * Indicates that the view is tracking some sort of transient state
      * that the app should not need to be aware of, but that the framework
      * should take special care to preserve.
@@ -1916,6 +1922,12 @@
     private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
 
     /**
+     * Default resolved text direction
+     * @hide
+     */
+    static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG;
+
+    /**
      * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
      * @hide
      */
@@ -1967,7 +1979,7 @@
      * @hide
      */
     static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT =
-            TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+            TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
 
     /*
      * Default text alignment. The text alignment of this View is inherited from its parent.
@@ -2026,6 +2038,12 @@
     private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
 
     /**
+     * Default resolved text alignment
+     * @hide
+     */
+    static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
+
+    /**
       * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
       * @hide
       */
@@ -2075,7 +2093,7 @@
      * Indicates whether if the view text alignment has been resolved to gravity
      */
     private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT =
-            TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+            TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
 
     // Accessiblity constants for mPrivateFlags2
 
@@ -5022,21 +5040,12 @@
 
             if ((mAttachInfo.mAccessibilityFetchFlags
                     & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0) {
-                String viewId = null;
                 try {
-                    viewId = getResources().getResourceName(mID);
+                    String viewId = getResources().getResourceName(mID);
+                    info.setViewIdResourceName(viewId);
                 } catch (Resources.NotFoundException nfe) {
                     /* ignore */
                 }
-                if (viewId == null) {
-                    try {
-                        viewId = ((Context) ActivityThread.currentActivityThread()
-                                .getSystemContext()).getResources().getResourceName(mID);
-                    } catch (Resources.NotFoundException nfe) {
-                        /* ignore */
-                    }
-                }
-                info.setViewIdResourceName(viewId);
             }
         }
 
@@ -5979,7 +5988,7 @@
         final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
         if (targetSdkVersion < JELLY_BEAN_MR1) {
             mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
-            return LAYOUT_DIRECTION_LTR;
+            return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
         }
         return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
                 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
@@ -9920,8 +9929,7 @@
             outRect.set(mLeft, mTop, mRight, mBottom);
         } else {
             final RectF tmpRect = mAttachInfo.mTmpTransformRect;
-            tmpRect.set(-info.mPivotX, -info.mPivotY,
-                    getWidth() - info.mPivotX, getHeight() - info.mPivotY);
+            tmpRect.set(0, 0, getWidth(), getHeight());
             info.mMatrix.mapRect(tmpRect);
             outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
                     (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
@@ -11805,11 +11813,10 @@
                     // later to get the correct resolved value
                     if (!canResolveLayoutDirection()) return false;
 
-                    View parent = ((View) mParent);
                     // Parent has not yet resolved, LTR is still the default
-                    if (!parent.isLayoutDirectionResolved()) return false;
+                    if (!mParent.isLayoutDirectionResolved()) return false;
 
-                    if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                    if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                         mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
                     }
                     break;
@@ -11842,8 +11849,7 @@
     public boolean canResolveLayoutDirection() {
         switch (getRawLayoutDirection()) {
             case LAYOUT_DIRECTION_INHERIT:
-                return (mParent != null) && (mParent instanceof ViewGroup) &&
-                       ((ViewGroup) mParent).canResolveLayoutDirection();
+                return (mParent != null) && mParent.canResolveLayoutDirection();
             default:
                 return true;
         }
@@ -11871,8 +11877,9 @@
 
     /**
      * @return true if layout direction has been resolved.
+     * @hide
      */
-    private boolean isLayoutDirectionResolved() {
+    public boolean isLayoutDirectionResolved() {
         return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
     }
 
@@ -16905,16 +16912,15 @@
                         return false;
                     }
 
-                    View parent = ((View) mParent);
                     // Parent has not yet resolved, so we still return the default
-                    if (!parent.isTextDirectionResolved()) {
+                    if (!mParent.isTextDirectionResolved()) {
                         mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
                         // Resolution will need to happen again later
                         return false;
                     }
 
                     // Set current resolved direction to the same value as the parent's one
-                    final int parentResolvedDirection = parent.getTextDirection();
+                    final int parentResolvedDirection = mParent.getTextDirection();
                     switch (parentResolvedDirection) {
                         case TEXT_DIRECTION_FIRST_STRONG:
                         case TEXT_DIRECTION_ANY_RTL:
@@ -16955,12 +16961,13 @@
      * Check if text direction resolution can be done.
      *
      * @return true if text direction resolution can be done otherwise return false.
+     *
+     * @hide
      */
-    private boolean canResolveTextDirection() {
+    public boolean canResolveTextDirection() {
         switch (getRawTextDirection()) {
             case TEXT_DIRECTION_INHERIT:
-                return (mParent != null) && (mParent instanceof View) &&
-                       ((View) mParent).canResolveTextDirection();
+                return (mParent != null) && mParent.canResolveTextDirection();
             default:
                 return true;
         }
@@ -16990,8 +16997,10 @@
 
     /**
      * @return true if text direction is resolved.
+     *
+     * @hide
      */
-    private boolean isTextDirectionResolved() {
+    public boolean isTextDirectionResolved() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
     }
 
@@ -17114,16 +17123,15 @@
                         // Resolution will need to happen again later
                         return false;
                     }
-                    View parent = (View) mParent;
 
                     // Parent has not yet resolved, so we still return the default
-                    if (!parent.isTextAlignmentResolved()) {
+                    if (!mParent.isTextAlignmentResolved()) {
                         mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
                         // Resolution will need to happen again later
                         return false;
                     }
 
-                    final int parentResolvedTextAlignment = parent.getTextAlignment();
+                    final int parentResolvedTextAlignment = mParent.getTextAlignment();
                     switch (parentResolvedTextAlignment) {
                         case TEXT_ALIGNMENT_GRAVITY:
                         case TEXT_ALIGNMENT_TEXT_START:
@@ -17168,12 +17176,13 @@
      * Check if text alignment resolution can be done.
      *
      * @return true if text alignment resolution can be done otherwise return false.
+     *
+     * @hide
      */
-    private boolean canResolveTextAlignment() {
+    public boolean canResolveTextAlignment() {
         switch (getRawTextAlignment()) {
             case TEXT_DIRECTION_INHERIT:
-                return (mParent != null) && (mParent instanceof View) &&
-                       ((View) mParent).canResolveTextAlignment();
+                return (mParent != null) && mParent.canResolveTextAlignment();
             default:
                 return true;
         }
@@ -17203,8 +17212,10 @@
 
     /**
      * @return true if text alignment is resolved.
+     *
+     * @hide
      */
-    private boolean isTextAlignmentResolved() {
+    public boolean isTextAlignmentResolved() {
         return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
     }
 
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index ddff91d..4b70bc0 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -295,4 +295,105 @@
      * @hide
      */
     public void childAccessibilityStateChanged(View child);
+
+    /**
+     * Tells if this view parent can resolve the layout direction.
+     * See {@link View#setLayoutDirection(int)}
+     *
+     * @return True if this view parent can resolve the layout direction.
+     *
+     * @hide
+     */
+    public boolean canResolveLayoutDirection();
+
+    /**
+     * Tells if this view parent layout direction is resolved.
+     * See {@link View#setLayoutDirection(int)}
+     *
+     * @return True if this view parent layout direction is resolved.
+     *
+     * @hide
+     */
+    public boolean isLayoutDirectionResolved();
+
+    /**
+     * Return this view parent layout direction. See {@link View#getLayoutDirection()}
+     *
+     * @return {@link View#LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
+     * {@link View#LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
+     *
+     * @hide
+     */
+    public int getLayoutDirection();
+
+    /**
+     * Tells if this view parent can resolve the text direction.
+     * See {@link View#setTextDirection(int)}
+     *
+     * @return True if this view parent can resolve the text direction.
+     *
+     * @hide
+     */
+    public boolean canResolveTextDirection();
+
+    /**
+     * Tells if this view parent text direction is resolved.
+     * See {@link View#setTextDirection(int)}
+     *
+     * @return True if this view parent text direction is resolved.
+     *
+     * @hide
+     */
+    public boolean isTextDirectionResolved();
+
+    /**
+     * Return this view parent text direction. See {@link View#getTextDirection()}
+     *
+     * @return the resolved text direction. Returns one of:
+     *
+     * {@link View#TEXT_DIRECTION_FIRST_STRONG}
+     * {@link View#TEXT_DIRECTION_ANY_RTL},
+     * {@link View#TEXT_DIRECTION_LTR},
+     * {@link View#TEXT_DIRECTION_RTL},
+     * {@link View#TEXT_DIRECTION_LOCALE}
+     *
+     * @hide
+     */
+    public int getTextDirection();
+
+    /**
+     * Tells if this view parent can resolve the text alignment.
+     * See {@link View#setTextAlignment(int)}
+     *
+     * @return True if this view parent can resolve the text alignment.
+     *
+     * @hide
+     */
+    public boolean canResolveTextAlignment();
+
+    /**
+     * Tells if this view parent text alignment is resolved.
+     * See {@link View#setTextAlignment(int)}
+     *
+     * @return True if this view parent text alignment is resolved.
+     *
+     * @hide
+     */
+    public boolean isTextAlignmentResolved();
+
+    /**
+     * Return this view parent text alignment. See {@link android.view.View#getTextAlignment()}
+     *
+     * @return the resolved text alignment. Returns one of:
+     *
+     * {@link View#TEXT_ALIGNMENT_GRAVITY},
+     * {@link View#TEXT_ALIGNMENT_CENTER},
+     * {@link View#TEXT_ALIGNMENT_TEXT_START},
+     * {@link View#TEXT_ALIGNMENT_TEXT_END},
+     * {@link View#TEXT_ALIGNMENT_VIEW_START},
+     * {@link View#TEXT_ALIGNMENT_VIEW_END}
+     *
+     * @hide
+     */
+    public int getTextAlignment();
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2df56c3..1d86361 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4829,6 +4829,51 @@
         postSendWindowContentChangedCallback(child);
     }
 
+    @Override
+    public boolean canResolveLayoutDirection() {
+        return true;
+    }
+
+    @Override
+    public boolean isLayoutDirectionResolved() {
+        return true;
+    }
+
+    @Override
+    public int getLayoutDirection() {
+        return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
+    }
+
+    @Override
+    public boolean canResolveTextDirection() {
+        return true;
+    }
+
+    @Override
+    public boolean isTextDirectionResolved() {
+        return true;
+    }
+
+    @Override
+    public int getTextDirection() {
+        return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
+    }
+
+    @Override
+    public boolean canResolveTextAlignment() {
+        return true;
+    }
+
+    @Override
+    public boolean isTextAlignmentResolved() {
+        return true;
+    }
+
+    @Override
+    public int getTextAlignment() {
+        return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+    }
+
     private View getCommonPredecessor(View first, View second) {
         if (mAttachInfo != null) {
             if (mTempHashSet == null) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 85ed8db..12cce8b 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1235,6 +1235,7 @@
             Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) continue;
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
@@ -1250,6 +1251,7 @@
             }
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) continue;
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index dbeb26d..deec41c 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -701,10 +701,15 @@
                 myWidth);
         int childHeightMeasureSpec;
         if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
-            // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
-            // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
-            // Carry it forward.
-            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            if (params.height >= 0) {
+                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        params.height, MeasureSpec.EXACTLY);
+            } else {
+                // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
+                // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
+                // Carry it forward.
+                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            }
         } else if (params.width == LayoutParams.MATCH_PARENT) {
             childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.EXACTLY);
         } else {
@@ -733,6 +738,9 @@
             int childSize, int startMargin, int endMargin, int startPadding,
             int endPadding, int mySize) {
         if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
+            if (childSize >= 0) {
+                return MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY);
+            }
             // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
             // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
             // Carry it forward.
@@ -1028,7 +1036,7 @@
         return -1;
     }
 
-    private void centerHorizontal(View child, LayoutParams params, int myWidth) {
+    private static void centerHorizontal(View child, LayoutParams params, int myWidth) {
         int childWidth = child.getMeasuredWidth();
         int left = (myWidth - childWidth) / 2;
 
@@ -1036,7 +1044,7 @@
         params.mRight = left + childWidth;
     }
 
-    private void centerVertical(View child, LayoutParams params, int myHeight) {
+    private static void centerVertical(View child, LayoutParams params, int myHeight) {
         int childHeight = child.getMeasuredHeight();
         int top = (myHeight - childHeight) / 2;
 
@@ -1230,6 +1238,7 @@
                     com.android.internal.R.styleable.RelativeLayout_Layout);
 
             final int[] rules = mRules;
+            //noinspection MismatchedReadAndWriteOfArray
             final int[] initialRules = mInitialRules;
 
             final int N = a.getIndexCount();
@@ -1308,9 +1317,7 @@
                 }
             }
 
-            for (int n = LEFT_OF; n < VERB_COUNT; n++) {
-                initialRules[n] = rules[n];
-            }
+            System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT);
 
             a.recycle();
         }
@@ -1401,9 +1408,7 @@
         private void resolveRules(int layoutDirection) {
             final boolean isLayoutRtl = (layoutDirection == View.LAYOUT_DIRECTION_RTL);
             // Reset to initial state
-            for (int n = LEFT_OF; n < VERB_COUNT; n++) {
-                mRules[n] = mInitialRules[n];
-            }
+            System.arraycopy(mInitialRules, LEFT_OF, mRules, LEFT_OF, VERB_COUNT);
             // Apply rules depending on direction
             if (mRules[ALIGN_START] != 0) {
                 mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2145419..cad7ae3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8801,11 +8801,11 @@
         }
 
         public void drawTextRun(Canvas c, int start, int end,
-                int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
+                int contextStart, int contextEnd, float x, float y, Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
-                    contextCount, x, y, flags, p);
+                    contextCount, x, y, p);
         }
 
         public float measureText(int start, int end, Paint p) {
@@ -8817,30 +8817,20 @@
         }
 
         public float getTextRunAdvances(int start, int end, int contextStart,
-                int contextEnd, int flags, float[] advances, int advancesIndex,
+                int contextEnd, float[] advances, int advancesIndex,
                 Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             return p.getTextRunAdvances(mChars, start + mStart, count,
-                    contextStart + mStart, contextCount, flags, advances,
+                    contextStart + mStart, contextCount, advances,
                     advancesIndex);
         }
 
-        public float getTextRunAdvances(int start, int end, int contextStart,
-                int contextEnd, int flags, float[] advances, int advancesIndex,
-                Paint p, int reserved) {
-            int count = end - start;
-            int contextCount = contextEnd - contextStart;
-            return p.getTextRunAdvances(mChars, start + mStart, count,
-                    contextStart + mStart, contextCount, flags, advances,
-                    advancesIndex, reserved);
-        }
-
-        public int getTextRunCursor(int contextStart, int contextEnd, int flags,
+        public int getTextRunCursor(int contextStart, int contextEnd,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
             return p.getTextRunCursor(mChars, contextStart + mStart,
-                    contextCount, flags, offset + mStart, cursorOpt);
+                    contextCount, offset + mStart, cursorOpt);
         }
     }
 
diff --git a/core/java/com/android/internal/app/IAppOpsCallback.aidl b/core/java/com/android/internal/app/IAppOpsCallback.aidl
index 4e75a61..afbc609 100644
--- a/core/java/com/android/internal/app/IAppOpsCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsCallback.aidl
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+// This interface is also used by native code, so must
+// be kept in sync with frameworks/native/include/binder/IAppOpsCallback.h
 oneway interface IAppOpsCallback {
     void opChanged(int op, String packageName);
 }
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 83967f6..a9da863 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -20,13 +20,17 @@
 import com.android.internal.app.IAppOpsCallback;
 
 interface IAppOpsService {
-    List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
-    List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
-    void setMode(int code, int uid, String packageName, int mode);
+    // These first methods are also called by native code, so must
+    // be kept in sync with frameworks/native/include/binder/IAppOpsService.h
     int checkOperation(int code, int uid, String packageName);
     int noteOperation(int code, int uid, String packageName);
     int startOperation(int code, int uid, String packageName);
     void finishOperation(int code, int uid, String packageName);
     void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
     void stopWatchingMode(IAppOpsCallback callback);
+
+    // Remaining methods are only used in Java.
+    List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
+    List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
+    void setMode(int code, int uid, String packageName, int mode);
 }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 6641f2c..28fd05f 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -820,7 +820,7 @@
              * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
              * always set msg.obj to the handler.
              */
-            boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);
+            boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);
 
             if (mLogRecords.logOnlyTransitions()) {
                 /** Record only if there is a transition */
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 7208c57..1f1f28f 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -727,35 +727,35 @@
 
     static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                      jfloat x, jfloat y, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, paint);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
     static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
-                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                          jfloat x, jfloat y, SkPaint* paint) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, paint);
         env->ReleaseStringChars(text, textArray);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, SkPaint* paint) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, paint);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, SkPaint* paint) {
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                textArray, start, count, contextCount, flags);
+                textArray, start, count, contextCount);
         if (value == NULL) {
             return;
         }
@@ -766,7 +766,7 @@
             x -= value->getTotalAdvance();
         }
         paint->setTextAlign(SkPaint::kLeft_Align);
-        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
+        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
     }
@@ -808,14 +808,8 @@
     }
 }
 
-    static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
-        // Beware: this needs Glyph encoding (already done on the Paint constructor)
-        canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
-    }
-
     static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
-            int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
+            int index, int count, jfloat x, jfloat y, SkPaint* paint) {
         SkPoint* posPtr = new SkPoint[count];
         for (int indx = 0; indx < count; indx++) {
             posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
@@ -832,7 +826,7 @@
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, paint);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
@@ -845,7 +839,7 @@
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, paint);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -908,21 +902,19 @@
 
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jcharArray text, int index, int count,
-            SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
+            SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
 
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
-                                   path, canvas);
+        TextLayout::drawTextOnPath(paint, textArray + index, count, hOffset, vOffset, path, canvas);
         env->ReleaseCharArrayElements(text, textArray, 0);
     }
 
     static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jstring text, SkPath* path,
-            jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
+            jfloat hOffset, jfloat vOffset, SkPaint* paint) {
         const jchar* text_ = env->GetStringChars(text, NULL);
         int count = env->GetStringLength(text);
-        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
-                                   path, canvas);
+        TextLayout::drawTextOnPath(paint, text_, count, hOffset, vOffset, path, canvas);
         env->ReleaseStringChars(text, text_);
     }
 
@@ -1031,21 +1023,21 @@
         (void*)SkCanvasGlue::drawBitmapMesh},
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
-    {"native_drawText","(I[CIIFFII)V",
+    {"native_drawText","(I[CIIFFI)V",
         (void*) SkCanvasGlue::drawText___CIIFFIPaint},
-    {"native_drawText","(ILjava/lang/String;IIFFII)V",
+    {"native_drawText","(ILjava/lang/String;IIFFI)V",
         (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
-    {"native_drawTextRun","(I[CIIIIFFII)V",
+    {"native_drawTextRun","(I[CIIIIFFI)V",
         (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
-    {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
+    {"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
         (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
         (void*) SkCanvasGlue::drawPosText__String_FPaint},
-    {"native_drawTextOnPath","(I[CIIIFFII)V",
+    {"native_drawTextOnPath","(I[CIIIFFI)V",
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
-    {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
+    {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
     {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 29a36de..e830492 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -401,7 +401,7 @@
         jfloat result = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &result);
+                NULL /* dont need all advances */, &result);
 
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
@@ -426,7 +426,7 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &width);
+                NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -446,7 +446,7 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &width);
+                NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
@@ -473,7 +473,7 @@
         jfloat* widthsArray = autoWidths.ptr();
 
         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
-                paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
+                widthsArray, NULL /* dont need totalAdvance */);
 
         return count;
     }
@@ -494,48 +494,8 @@
         return count;
     }
 
-    static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
-            jint contextCount, jint flags, jcharArray glyphs) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-        size_t glypthsLength = env->GetArrayLength(glyphs);
-        if ((size_t)count > glypthsLength) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-
-        jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
-
-        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                text, start, count, contextCount, flags);
-        const jchar* shapedGlyphs = value->getGlyphs();
-        size_t glyphsCount = value->getGlyphsCount();
-        memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
-
-        env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
-        return glyphsCount;
-    }
-
-    static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
-            jcharArray glyphs) {
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
-                end - start, contextEnd - contextStart, flags, glyphs);
-        env->ReleaseStringChars(text, textArray);
-        return count;
-    }
-
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
-                                    jint start, jint count, jint contextCount, jint flags,
+                                    jint start, jint count, jint contextCount,
                                     jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
@@ -557,7 +517,7 @@
         jfloat advancesArray[count];
         jfloat totalAdvance = 0;
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
+        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount,
                                        advancesArray, &totalAdvance);
 
         if (advances != NULL) {
@@ -566,61 +526,23 @@
         return totalAdvance;
     }
 
-    static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
-                                    jint start, jint count, jint contextCount, jint flags,
-                                    jfloatArray advances, jint advancesIndex) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-        if (advances) {
-            size_t advancesLength = env->GetArrayLength(advances);
-            if ((size_t)count > advancesLength) {
-                doThrowAIOOBE(env);
-                return 0;
-            }
-        }
-
-        jfloat advancesArray[count];
-        jfloat totalAdvance = 0;
-
-        TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
-                                       advancesArray, totalAdvance);
-
-        if (advances != NULL) {
-            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
-        }
-        return totalAdvance;
-    }
-
-    static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static float getTextRunAdvances___CIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
-            jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
+            jfloatArray advances, jint advancesIndex) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jfloat result = (reserved == 0) ?
-                doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
-                        count, contextCount, flags, advances, advancesIndex) :
-                doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
-                        count, contextCount, flags, advances, advancesIndex);
+        jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
+                index - contextIndex, count, contextCount, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
-    static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
-            jfloatArray advances, jint advancesIndex, jint reserved) {
+    static float getTextRunAdvances__StringIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd,
+            jfloatArray advances, jint advancesIndex) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        jfloat result = (reserved == 0) ?
-                doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
-                        end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
-                doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
-                        end - start, contextEnd - contextStart, flags, advances, advancesIndex);
+        jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
+                start - contextStart, end - start, contextEnd - contextStart,
+                advances, advancesIndex);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
@@ -629,7 +551,7 @@
             jint count, jint flags, jint offset, jint opt) {
         jfloat scalarArray[count];
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
+        TextLayout::getTextRunAdvances(paint, text, start, count, start + count,
                 scalarArray, NULL /* dont need totalAdvance */);
 
         jint pos = offset - start;
@@ -688,21 +610,21 @@
     }
 
     static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
-                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
-        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
+                            jfloat x, jfloat y, SkPath *path) {
+        TextLayout::getTextPath(paint, text, count, x, y, path);
     }
 
-    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
+    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint,
             jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
+        getTextPath(env, paint, textArray + index, count, x, y, path);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
     }
 
-    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
+    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint,
             jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
+        getTextPath(env, paint, textArray + start, end - start, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
 
@@ -726,7 +648,7 @@
                          int count, float maxWidth, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, paint.getFlags());
+                text, 0, count, count);
         if (value == NULL) {
             return 0;
         }
@@ -798,7 +720,7 @@
         SkIRect ir;
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, paint.getFlags());
+                text, 0, count, count);
         if (value == NULL) {
             return;
         }
@@ -886,19 +808,15 @@
     {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
     {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
     {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
-    {"native_getTextRunAdvances","(I[CIIIII[FII)F",
-        (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
-    {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
-        (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
-
-
-    {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
-        (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
-    {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
-    {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
+    {"native_getTextRunAdvances","(I[CIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances___CIIII_FI},
+    {"native_getTextRunAdvances","(ILjava/lang/String;IIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances__StringIIII_FI},
+    {"native_getTextRunCursor", "(I[CIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
+    {"native_getTextRunCursor", "(ILjava/lang/String;IIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
-    {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
-    {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
+    {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
+    {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
     {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
                                         (void*) SkPaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 2beedad..b77236c 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -28,33 +28,13 @@
 
 namespace android {
 
-// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
-// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
-// looking for a character >= the first RTL character in unicode and assume we do if
-// we find one.
-bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
-    if (bidiFlags == kBidi_Force_LTR) {
-        return false;
-    }
-    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
-            bidiFlags == kBidi_Force_RTL) {
-        return true;
-    }
-    for (int i = 0; i < len; ++i) {
-        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
-            return true;
-        }
-    }
-    return false;
-}
-
 // Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
 // This will draw if canvas is not null, otherwise path must be non-null and it will create
 // a path representing the text that would have been drawn.
 void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
-                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+                            jfloat x, jfloat y, SkPath *path) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, len, len, bidiFlags);
+            text, 0, len, len);
     if (value == NULL) {
         return ;
     }
@@ -65,10 +45,10 @@
 }
 
 void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                    jint count, jint contextCount, jint dirFlags,
+                                    jint count, jint contextCount,
                                     jfloat* resultAdvances, jfloat* resultTotalAdvance) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            chars, start, count, contextCount, dirFlags);
+            chars, start, count, contextCount);
     if (value == NULL) {
         return ;
     }
@@ -80,29 +60,20 @@
     }
 }
 
-void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
-                                    jint count, jint contextCount, jint dirFlags,
-                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
-    // Compute advances and return them
-    computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
-            resultAdvances, &resultTotalAdvance);
-}
-
 void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
-                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
-    handleText(paint, text, len, bidiFlags, x, y, path);
+                             jfloat x, jfloat y, SkPath *path) {
+    handleText(paint, text, len, x, y, path);
 }
 
-
 void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
-                                int bidiFlags, jfloat hOffset, jfloat vOffset,
+                                jfloat hOffset, jfloat vOffset,
                                 SkPath* path, SkCanvas* canvas) {
 
     SkScalar h_ = SkFloatToScalar(hOffset);
     SkScalar v_ = SkFloatToScalar(vOffset);
 
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, bidiFlags);
+            text, 0, count, count);
     if (value == NULL) {
         return;
     }
@@ -111,73 +82,4 @@
     canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
 }
 
-void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount, int dirFlags,
-        jfloat* outAdvances, jfloat* outTotalAdvance) {
-    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
-    jchar* buffer = tempBuffer.get();
-    SkScalar* scalarArray = (SkScalar*)outAdvances;
-
-    // this is where we'd call harfbuzz
-    // for now we just use ushape.c
-    size_t widths;
-    const jchar* text;
-    if (dirFlags & 0x1) { // rtl, call arabic shaping in case
-        UErrorCode status = U_ZERO_ERROR;
-        // Use fixed length since we need to keep start and count valid
-        u_shapeArabic(chars, contextCount, buffer, contextCount,
-                U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
-                U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
-                U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
-        // we shouldn't fail unless there's an out of memory condition,
-        // in which case we're hosed anyway
-        for (int i = start, e = i + count; i < e; ++i) {
-            if (buffer[i] == UNICODE_NOT_A_CHAR) {
-                buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
-            }
-        }
-        text = buffer + start;
-        widths = paint->getTextWidths(text, count << 1, scalarArray);
-    } else {
-        text = chars + start;
-        widths = paint->getTextWidths(text, count << 1, scalarArray);
-    }
-
-    jfloat totalAdvance = 0;
-    if (widths < count) {
-#if DEBUG_ADVANCES
-    ALOGD("ICU -- count=%d", widths);
-#endif
-        // Skia operates on code points, not code units, so surrogate pairs return only
-        // one value. Expand the result so we have one value per UTF-16 code unit.
-
-        // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
-        // leaving the remaining widths zero.  Not nice.
-        for (size_t i = 0, p = 0; i < widths; ++i) {
-            totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]);
-            if (p < count &&
-                    text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
-                    text[p] < UNICODE_FIRST_PRIVATE_USE &&
-                    text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
-                    text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
-                outAdvances[p++] = 0;
-            }
-#if DEBUG_ADVANCES
-            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
-#endif
-        }
-    } else {
-#if DEBUG_ADVANCES
-    ALOGD("ICU -- count=%d", count);
-#endif
-        for (size_t i = 0; i < count; i++) {
-            totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
-#if DEBUG_ADVANCES
-            ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
-#endif
-        }
-    }
-    *outTotalAdvance = totalAdvance;
-}
-
 }
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index a0f9402..fa388c8 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -42,17 +42,6 @@
 #define USE_TEXT_LAYOUT_CACHE 1
 
 enum {
-    kBidi_LTR = 0,
-    kBidi_RTL = 1,
-    kBidi_Default_LTR = 2,
-    kBidi_Default_RTL = 3,
-    kBidi_Force_LTR = 4,
-    kBidi_Force_RTL = 5,
-
-    kBidi_Mask = 0x7
-};
-
-enum {
     kDirection_LTR = 0,
     kDirection_RTL = 1,
 
@@ -63,28 +52,18 @@
 public:
 
     static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                   jint count, jint contextCount, jint dirFlags,
+                                   jint count, jint contextCount,
                                    jfloat* resultAdvances, jfloat* resultTotalAdvance);
 
-    static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
-                                   jint count, jint contextCount, jint dirFlags,
-                                   jfloat* resultAdvances, jfloat& resultTotalAdvance);
-
     static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
-                            jint bidiFlags, jfloat x, jfloat y, SkPath* path);
+                            jfloat x, jfloat y, SkPath* path);
 
     static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
-                               int bidiFlags, jfloat hOffset, jfloat vOffset,
+                               jfloat hOffset, jfloat vOffset,
                                SkPath* path, SkCanvas* canvas);
 
 private:
-    static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
-
     static void handleText(SkPaint* paint, const jchar* text, jsize len,
-                           int bidiFlags, jfloat x, jfloat y, SkPath* path);
-
-    static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, int dirFlags,
-            jfloat* outAdvances, jfloat* outTotalAdvance);
+                           jfloat x, jfloat y, SkPath* path);
 };
 } // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 7544645..1a8612e 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -87,7 +87,7 @@
  * Caching
  */
 sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
-            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
+            const jchar* text, jint start, jint count, jint contextCount) {
     AutoMutex _l(mLock);
     nsecs_t startTime = 0;
     if (mDebugEnabled) {
@@ -95,7 +95,7 @@
     }
 
     // Create the key
-    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
+    TextLayoutCacheKey key(paint, text, start, count, contextCount);
 
     // Get value from cache if possible
     sp<TextLayoutValue> value = mCache.get(key);
@@ -111,7 +111,7 @@
         // Compute advances and store them
         mShaper->computeValues(value.get(), paint,
                 reinterpret_cast<const UChar*>(key.getText()), start, count,
-                size_t(contextCount), int(dirFlags));
+                size_t(contextCount));
 
         if (mDebugEnabled) {
             value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
@@ -218,14 +218,13 @@
  * TextLayoutCacheKey
  */
 TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
-        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
+        typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
         hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
-        size_t start, size_t count, size_t contextCount, int dirFlags) :
-            start(start), count(count), contextCount(contextCount),
-            dirFlags(dirFlags) {
+        size_t start, size_t count, size_t contextCount) :
+            start(start), count(count), contextCount(contextCount) {
     textCopy.setTo(text, contextCount);
     typeface = paint->getTypeface();
     textSize = paint->getTextSize();
@@ -242,7 +241,6 @@
         start(other.start),
         count(other.count),
         contextCount(other.contextCount),
-        dirFlags(other.dirFlags),
         typeface(other.typeface),
         textSize(other.textSize),
         textSkewX(other.textSkewX),
@@ -281,9 +279,6 @@
     deltaInt = lhs.hinting - rhs.hinting;
     if (deltaInt != 0) return (deltaInt);
 
-    deltaInt = lhs.dirFlags - rhs.dirFlags;
-    if (deltaInt) return (deltaInt);
-
     deltaInt = lhs.variant - rhs.variant;
     if (deltaInt) return (deltaInt);
 
@@ -359,9 +354,9 @@
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount, int dirFlags) {
+        size_t start, size_t count, size_t contextCount) {
 
-    computeValues(paint, chars, start, count, contextCount, dirFlags,
+    computeValues(paint, chars, start, count, contextCount,
             &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
 #if DEBUG_ADVANCES
     ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
@@ -370,7 +365,7 @@
 }
 
 void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount, int dirFlags,
+        size_t start, size_t count, size_t contextCount,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
         *outTotalAdvance = 0;
@@ -378,110 +373,94 @@
             return;
         }
 
-        UBiDiLevel bidiReq = 0;
-        bool forceLTR = false;
-        bool forceRTL = false;
-
-        switch (dirFlags & kBidi_Mask) {
-            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
-            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
-            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
-            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
-            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
-            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
-        }
-
+        UBiDiLevel bidiReq = UBIDI_DEFAULT_LTR;
         bool useSingleRun = false;
-        bool isRTL = forceRTL;
-        if (forceLTR || forceRTL) {
-            useSingleRun = true;
-        } else {
-            UBiDi* bidi = ubidi_open();
-            if (bidi) {
-                UErrorCode status = U_ZERO_ERROR;
+        bool isRTL = false;
+
+        UBiDi* bidi = ubidi_open();
+        if (bidi) {
+            UErrorCode status = U_ZERO_ERROR;
 #if DEBUG_GLYPHS
-                ALOGD("******** ComputeValues -- start");
-                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
-                ALOGD("      -- start = %d", start);
-                ALOGD("      -- count = %d", count);
-                ALOGD("      -- contextCount = %d", contextCount);
-                ALOGD("      -- bidiReq = %d", bidiReq);
+            ALOGD("******** ComputeValues -- start");
+            ALOGD("      -- string = '%s'", String8(chars + start, count).string());
+            ALOGD("      -- start = %d", start);
+            ALOGD("      -- count = %d", count);
+            ALOGD("      -- contextCount = %d", contextCount);
+            ALOGD("      -- bidiReq = %d", bidiReq);
 #endif
-                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
-                if (U_SUCCESS(status)) {
-                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
-                    ssize_t rc = ubidi_countRuns(bidi, &status);
+            ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
+            if (U_SUCCESS(status)) {
+                int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
+                ssize_t rc = ubidi_countRuns(bidi, &status);
 #if DEBUG_GLYPHS
-                    ALOGD("      -- dirFlags = %d", dirFlags);
-                    ALOGD("      -- paraDir = %d", paraDir);
-                    ALOGD("      -- run-count = %d", int(rc));
+                ALOGD("      -- paraDir = %d", paraDir);
+                ALOGD("      -- run-count = %d", int(rc));
 #endif
-                    if (U_SUCCESS(status) && rc == 1) {
-                        // Normal case: one run, status is ok
-                        isRTL = (paraDir == 1);
-                        useSingleRun = true;
-                    } else if (!U_SUCCESS(status) || rc < 1) {
-                        ALOGW("Need to force to single run -- string = '%s',"
-                                " status = %d, rc = %d",
-                                String8(chars + start, count).string(), status, int(rc));
-                        isRTL = (paraDir == 1);
-                        useSingleRun = true;
-                    } else {
-                        int32_t end = start + count;
-                        for (size_t i = 0; i < size_t(rc); ++i) {
-                            int32_t startRun = -1;
-                            int32_t lengthRun = -1;
-                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
-
-                            if (startRun == -1 || lengthRun == -1) {
-                                // Something went wrong when getting the visual run, need to clear
-                                // already computed data before doing a single run pass
-                                ALOGW("Visual run is not valid");
-                                outGlyphs->clear();
-                                outAdvances->clear();
-                                outPos->clear();
-                                *outTotalAdvance = 0;
-                                isRTL = (paraDir == 1);
-                                useSingleRun = true;
-                                break;
-                            }
-
-                            if (startRun >= end) {
-                                continue;
-                            }
-                            int32_t endRun = startRun + lengthRun;
-                            if (endRun <= int32_t(start)) {
-                                continue;
-                            }
-                            if (startRun < int32_t(start)) {
-                                startRun = int32_t(start);
-                            }
-                            if (endRun > end) {
-                                endRun = end;
-                            }
-
-                            lengthRun = endRun - startRun;
-                            isRTL = (runDir == UBIDI_RTL);
-#if DEBUG_GLYPHS
-                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
-                                    i, startRun, lengthRun, isRTL);
-#endif
-                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
-                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
-
-                        }
-                    }
-                } else {
-                    ALOGW("Cannot set Para");
+                if (U_SUCCESS(status) && rc == 1) {
+                    // Normal case: one run, status is ok
+                    isRTL = (paraDir == 1);
                     useSingleRun = true;
-                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
+                } else if (!U_SUCCESS(status) || rc < 1) {
+                    ALOGW("Need to force to single run -- string = '%s',"
+                            " status = %d, rc = %d",
+                            String8(chars + start, count).string(), status, int(rc));
+                    isRTL = (paraDir == 1);
+                    useSingleRun = true;
+                } else {
+                    int32_t end = start + count;
+                    for (size_t i = 0; i < size_t(rc); ++i) {
+                        int32_t startRun = -1;
+                        int32_t lengthRun = -1;
+                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+
+                        if (startRun == -1 || lengthRun == -1) {
+                            // Something went wrong when getting the visual run, need to clear
+                            // already computed data before doing a single run pass
+                            ALOGW("Visual run is not valid");
+                            outGlyphs->clear();
+                            outAdvances->clear();
+                            outPos->clear();
+                            *outTotalAdvance = 0;
+                            isRTL = (paraDir == 1);
+                            useSingleRun = true;
+                            break;
+                        }
+
+                        if (startRun >= end) {
+                            continue;
+                        }
+                        int32_t endRun = startRun + lengthRun;
+                        if (endRun <= int32_t(start)) {
+                            continue;
+                        }
+                        if (startRun < int32_t(start)) {
+                            startRun = int32_t(start);
+                        }
+                        if (endRun > end) {
+                            endRun = end;
+                        }
+
+                        lengthRun = endRun - startRun;
+                        isRTL = (runDir == UBIDI_RTL);
+#if DEBUG_GLYPHS
+                        ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
+                                i, startRun, lengthRun, isRTL);
+#endif
+                        computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
+                                outAdvances, outTotalAdvance, outGlyphs, outPos);
+
+                    }
                 }
-                ubidi_close(bidi);
             } else {
-                ALOGW("Cannot ubidi_open()");
+                ALOGW("Cannot set Para");
                 useSingleRun = true;
                 isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
             }
+            ubidi_close(bidi);
+        } else {
+            ALOGW("Cannot ubidi_open()");
+            useSingleRun = true;
+            isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
         }
 
         // Default single run case
@@ -785,10 +764,6 @@
 /**
  * Return the first typeface in the logical change, starting with this typeface,
  * that contains the specified unichar, or NULL if none is found.
- * 
- * Note that this function does _not_ increment the reference count on the typeface, as the
- * assumption is that its lifetime is managed elsewhere - in particular, the fallback typefaces
- * for the default font live in a global cache.
  */
 SkTypeface* TextLayoutShaper::typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
         hb_script_t script) {
@@ -798,7 +773,7 @@
     }
     typeface = SkCreateTypefaceForScriptNG(script, currentStyle);
 #if DEBUG_GLYPHS
-    ALOGD("Using Harfbuzz Script %d, Style %d", script, currentStyle);
+    ALOGD("Using Harfbuzz Script %c%c%c%c, Style %d", HB_UNTAG(script), currentStyle);
 #endif
     return typeface;
 }
@@ -845,6 +820,7 @@
     if (baseGlyphCount != 0) {
         typeface = typefaceForScript(paint, typeface, hb_buffer_get_script(mBuffer));
         if (!typeface) {
+            baseGlyphCount = 0;
             typeface = mDefaultTypeface;
             SkSafeRef(typeface);
 #if DEBUG_GLYPHS
@@ -921,11 +897,11 @@
 }
 
 sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
-        jint start, jint count, jint contextCount, jint dirFlags) {
+        jint start, jint count, jint contextCount) {
     sp<TextLayoutValue> value;
 #if USE_TEXT_LAYOUT_CACHE
     value = mTextLayoutCache->getValue(paint, text, start, count,
-            contextCount, dirFlags);
+            contextCount);
     if (value == NULL) {
         ALOGE("Cannot get TextLayoutCache value for text = '%s'",
                 String8(text + start, count).string());
@@ -933,7 +909,7 @@
 #else
     value = new TextLayoutValue(count);
     mShaper->computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
+            reinterpret_cast<const UChar*>(text), start, count, contextCount);
 #endif
     return value;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 704c773..29805ee 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -71,7 +71,7 @@
     TextLayoutCacheKey();
 
     TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
-            size_t contextCount, int dirFlags);
+            size_t contextCount);
 
     TextLayoutCacheKey(const TextLayoutCacheKey& other);
 
@@ -98,7 +98,6 @@
     size_t start;
     size_t count;
     size_t contextCount;
-    int dirFlags;
     SkTypeface* typeface;
     SkScalar textSize;
     SkScalar textSkewX;
@@ -182,7 +181,7 @@
     virtual ~TextLayoutShaper();
 
     void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, int dirFlags);
+            size_t start, size_t count, size_t contextCount);
 
     void purgeCaches();
 
@@ -216,7 +215,7 @@
     size_t shapeFontRun(const SkPaint* paint);
 
     void computeValues(const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount, int dirFlags,
+            size_t start, size_t count, size_t contextCount,
             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
@@ -253,7 +252,7 @@
     void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
 
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount, jint dirFlags);
+            jint count, jint contextCount);
 
     /**
      * Clear the cache
@@ -305,7 +304,7 @@
      * the call. Be careful of this when doing optimization.
      **/
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount, jint dirFlags);
+            jint count, jint contextCount);
 
     void purgeCaches();
 
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 631cdae..0827f7c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -76,6 +76,15 @@
 }
 
 static jboolean
+android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
+        jint inPastMs)
+{
+    bool state = false;
+    AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
+    return state;
+}
+
+static jboolean
 android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
 {
     bool state = false;
@@ -270,6 +279,7 @@
     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
     {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
     {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
+    {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
     {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d422951..785bf13 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -685,6 +685,10 @@
                                                            jobject outValue,
                                                            jboolean resolve)
 {
+    if (outValue == NULL) {
+         jniThrowNullPointerException(env, "outValue");
+         return NULL;
+    }
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
         return 0;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 895a0dc..c08178d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -567,9 +567,9 @@
 // ----------------------------------------------------------------------------
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
-        jfloat x, jfloat y, int flags, SkPaint* paint) {
+        jfloat x, jfloat y, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, flags);
+            text, 0, count, count);
     if (value == NULL) {
         return;
     }
@@ -583,9 +583,9 @@
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, flags);
+            text, 0, count, count);
     if (value == NULL) {
         return;
     }
@@ -598,9 +598,9 @@
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
-        int flags, SkPaint* paint) {
+        SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, start, count, contextCount, flags);
+            text, start, count, contextCount);
     if (value == NULL) {
         return;
     }
@@ -615,64 +615,62 @@
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jfloat x, jfloat y, jint flags, SkPaint* paint) {
+        jfloat x, jfloat y, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
-    renderText(renderer, textArray + index, count, x, y, flags, paint);
+    renderText(renderer, textArray + index, count, x, y, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jfloat x, jfloat y, jint flags, SkPaint* paint) {
+        jfloat x, jfloat y, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
-    renderText(renderer, textArray + start, end - start, x, y, flags, paint);
+    renderText(renderer, textArray + start, end - start, x, y, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, flags, paint);
+            hOffset, vOffset, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, flags, paint);
+            hOffset, vOffset, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
-        SkPaint* paint) {
+        jint contextIndex, jint contextCount, jfloat x, jfloat y, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
-            count, contextCount, x, y, dirFlags, paint);
+            count, contextCount, x, y, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
  }
 
 static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
-        SkPaint* paint) {
+        jint contextStart, int contextEnd, jfloat x, jfloat y, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
     renderTextRun(renderer, textArray + contextStart, start - contextStart,
-            count, contextCount, x, y, dirFlags, paint);
+            count, contextCount, x, y, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
-        const jfloat* positions, jint dirFlags, SkPaint* paint) {
+        const jfloat* positions, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, dirFlags);
+            text, 0, count, count);
     if (value == NULL) {
         return;
     }
@@ -690,7 +688,7 @@
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + index, count, positions, kBidi_LTR, paint);
+    renderPosText(renderer, textArray + index, count, positions, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -702,7 +700,7 @@
     const jchar* textArray = env->GetStringChars(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + start, end - start, positions, kBidi_LTR, paint);
+    renderPosText(renderer, textArray + start, end - start, positions, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseStringChars(text, textArray);
@@ -1025,16 +1023,16 @@
     { "nSetupPaintFilter",  "(III)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(I)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
 
-    { "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
-    { "nDrawText",          "(ILjava/lang/String;IIFFII)V",
+    { "nDrawText",          "(I[CIIFFI)V",    (void*) android_view_GLES20Canvas_drawTextArray },
+    { "nDrawText",          "(ILjava/lang/String;IIFFI)V",
             (void*) android_view_GLES20Canvas_drawText },
 
-    { "nDrawTextOnPath",    "(I[CIIIFFII)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
-    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFII)V",
+    { "nDrawTextOnPath",    "(I[CIIIFFI)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
+    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFI)V",
             (void*) android_view_GLES20Canvas_drawTextOnPath },
 
-    { "nDrawTextRun",       "(I[CIIIIFFII)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
-    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFII)V",
+    { "nDrawTextRun",       "(I[CIIIIFFI)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
+    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFI)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
 
     { "nDrawPosText",       "(I[CII[FI)V",     (void*) android_view_GLES20Canvas_drawPosTextArray },
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 22f4fdc..cfc791d 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -42,7 +42,3 @@
 
 # Make sure the system .rs files get compiled before building the package-export.apk.
 # $(resource_export_package): $(framework_RenderScript_STAMP_FILE)
-
-# define a global intermediate target that other module may depend on.
-.PHONY: framework-res-package-target
-framework-res-package-target: $(LOCAL_BUILT_MODULE)
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 960232a..c1cb9d59 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 7f351da..158134e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Разрешава на приложението да управлява правилата на мрежата и да определя такива за конкретно приложение."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"промяна на отчетността на употребата на мрежа"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index de1f9aa..e3ee35d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0b1715e..35798a4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 860a9be..477f313 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3a8c6ab..770cc61 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9f7399b..40fc411 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ec2a60e..4af1886 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c6be92d..8517662 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6c0761c..2b657c8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 26482bd..3303f00 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5e8ac2b..b4a15c5 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه می‎دهد تا خط مشی‎های شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‎های عادی نیست."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 43cd8ab..45f4a05 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Sallii sovelluksen hallinnoida verkkokäytäntöjä ja määritellä sovelluskohtaisia sääntöjä."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verkon käytön seurannan muokkaaminen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b5d2d2b..c94946e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet à l\'application de gérer les stratégies du réseau et de définir celles qui sont spécifiques à l\'application."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifier le système de comptabilisation de l\'utilisation du réseau"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8175fa4..3521f4b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्‍लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्‍लिकेशन-विशिष्‍ट नियमों को परिभाषित करने देता है."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्‍लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 4773c941..ce7e954 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a6ea0f6..a472123 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hálózati irányelveket és meghatározza az alkalmazásspecifikus szabályokat."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"hálózathasználat elszámolásának módosítása"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 72199a1..d0b4d61 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"mengubah penghitungan penggunaan jaringan"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1c95e73..87d21fe 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 333aaa9..53fbeb4 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"앱이 네트워크 정책을 관리하고 앱별 규칙을 정의할 수 있도록 허용합니다."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"네트워크 사용량 계산 수정"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a3460d16..3b6e440 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Leidžiama programai valdyti tinklo politiką ir apibrėžti konkrečios programos taisykles."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"keisti tinklo naudojimo apskaitą"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index e92fa7d..646b7fa 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ļauj lietotnei pārvaldīt tīkla politikas un noteikt lietotnes kārtulas."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Tīkla lietojuma uzskaites mainīšana"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0f30f40..784a424 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Membenarkan apl mengurus dasar rangkaian dan menentukan peraturan khusus apl."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ubah suai perakaunan penggunaan rangkaian"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 1cb41c4..485a11f8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 757a813..95da93b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a5405de..f15c106 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pozwala aplikacji na zarządzanie zasadami dotyczącymi sieci i definiowanie reguł aplikacji."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modyfikowanie sposobu naliczania użycia sieci"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 28b6f9d..186eb3e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bcec57e..a2c6675 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que o aplicativo gerencie políticas de rede e definia regras específicas para o aplicativo."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contagem de uso da rede"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 52fee9b..e6d142b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicaţiei să gestioneze politicile de reţea şi să definească regulile specifice aplicaţiilor."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 741d78f..fa623e0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Приложение сможет управлять сетевыми политиками и определять правила для отдельных приложений."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"изменение учета использования сети"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ к уведомлениям"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e0126da..5f49e68 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 73d308c..aa240de 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 127d5eb..7a3ff07 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index aab6047..eca52e6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillåter att appen hanterar nätverkspolicyer och definierar appspecifika regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ändra nätverksredovisningen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 109566f..554921b 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -190,8 +190,8 @@
     <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Soma maneno katika kamusi ya mtumiaji."</string>
     <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Andika Kamusi ya Mtumiaji"</string>
     <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Ongeza maneno katika kamusi mtumiaji."</string>
-    <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Vialamisho na Historia"</string>
-    <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Kufikia moja kwa moja vialamisho na historia ya kivinjari"</string>
+    <string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Alamisho na Historia"</string>
+    <string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Kufikia, moja kwa moja, alamisho na historia ya kivinjari."</string>
     <string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Kengele"</string>
     <string name="permgroupdesc_deviceAlarms" msgid="4769356362251641175">"Weka saa ya kengele."</string>
     <string name="permgrouplab_voicemail" msgid="4162237145027592133">"Barua ya sauti"</string>
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
@@ -865,8 +863,8 @@
     <string name="js_dialog_before_unload" msgid="730366588032430474">"Toka kwa ukurasa huu?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Gusa Sawa ili kuendelea, au Ghairi ili kubaki kwenye ukurasa wa sasa."</string>
     <string name="save_password_label" msgid="6860261758665825069">"Thibitisha"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kidokezo: Gonga mara mbili ili kukuza ndani na nje."</string>
-    <string name="autofill_this_form" msgid="4616758841157816676">"Mjazo-otomatiki"</string>
-    <string name="setup_autofill" msgid="7103495070180590814">"Sanidi Mjazo-otomati"</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"Kujaza kiotomatiki"</string>
+    <string name="setup_autofill" msgid="7103495070180590814">"Weka uwezo wa kujaza kiotomatiki"</string>
     <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
     <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -887,7 +885,7 @@
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Inaruhusu programu kusoma historia ya URL zote ambazo zimetembelewa na Kivinjari, na alamisho zote za Kivinjari. Kumbuka: idhini hii haiwezi kutekelezwa vivinjari vya vingine au programu zingine zenye uwezo wa kuvinjari."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"andika alamisho na historia ya wavuti"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Inaruhusu programu kurekebisha historia ya Kivinjari au alamisho zilizohifadhiwa kwenye kompyuta kibao yako. Hii inaruhusu programu kufuta au kurekebisha data ya Kivinjari. Kumbuka: huenda idhini hii isitekelezwe na kivinjari kingine au programu nyingine zenye uwezo wa kuvinjari wavuti."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Inaruhusu programu kurekebisha historia ya Kivinjari au vialamisho vilivyohifadhiwa kwenye simu yako. Hii huenda ikaruhusu programu kufuta au kurekebisha data ya Kivinjari. Kumbuka: huenda idhini hii isitekelezwe na vivinjari vingine au programu nyingine zenye uwezo wa kuvinjari wavuti."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Inaruhusu programu kurekebisha historia ya Kivinjari au alamisho zilizohifadhiwa kwenye simu yako. Hii huenda ikaruhusu programu kufuta au kurekebisha data ya Kivinjari. Kumbuka: huenda idhini hii isitekelezwe na vivinjari vingine au programu nyingine zenye uwezo wa kuvinjari wavuti."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"weka kengele"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Inaruhusu programu kuweka kengele katika programu iliyosakinishwa ya kengele. Programu zingine za kengele zinawezakosa kutekeleza kipengee hiki."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"ongeza barua ya sauti"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e7d4b4f..e7df782 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"อนุญาตให้แอปพลิเคชันจัดการนโยบายเครือข่ายและกำหนดกฎเฉพาะแอปพลิเคชัน"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกคืน ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0021828..6268786 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pinapayagan ang app na pamahalaan ang mga patakaran ng network at ilarawan ang mga patakarang tukoy sa app."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"baguhin ang pagkukuwenta sa paggamit ng network"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e2c505b..21fe6d4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 0563f8c..7f80706 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e4da91a..1406064 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允许应用管理网络政策和定义专门针对应用的规则。"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改网络使用情况记录方式"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"查看通知"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 757ed6c..30893c6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -617,10 +617,8 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
-    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
-    <skip />
-    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
-    <skip />
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 649e39d..0461c0b 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -213,8 +213,8 @@
                         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
                         // Initialize other fields.
                         config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
-                        config.enterpriseConfig.setCaCertificate("");
-                        config.enterpriseConfig.setClientCertificate("");
+                        config.enterpriseConfig.setCaCertificateAlias("");
+                        config.enterpriseConfig.setClientCertificateAlias("");
                         config.enterpriseConfig.setIdentity("");
                         config.enterpriseConfig.setAnonymousIdentity("");
                         break;
@@ -288,12 +288,12 @@
             }
             if (cacert) {
                 String cacertValue = new String(ch, start, length);
-                config.enterpriseConfig.setCaCertificate(cacertValue);
+                config.enterpriseConfig.setCaCertificateAlias(cacertValue);
                 cacert = false;
             }
             if (usercert) {
                 String usercertValue = new String(ch, start, length);
-                config.enterpriseConfig.setClientCertificate(usercertValue);
+                config.enterpriseConfig.setClientCertificateAlias(usercertValue);
                 usercert = false;
             }
             if (ip) {
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index cf04b5c..d986c1e 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -122,71 +122,6 @@
          others should have a fairly open environment in which to
          interact with the system. -->
 
-    <!-- Standard permissions granted to the shell. -->
-    <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
-    <assign-permission name="android.permission.SEND_SMS" uid="shell" />
-    <assign-permission name="android.permission.CALL_PHONE" uid="shell" />
-    <assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
-    <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
-    <assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
-    <assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" />
-    <assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" />
-    <assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
-    <assign-permission name="android.permission.BLUETOOTH" uid="shell" />
-    <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" />
-    <!-- System tool permissions granted to the shell. -->
-    <assign-permission name="android.permission.GET_TASKS" uid="shell" />
-    <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
-    <assign-permission name="android.permission.REORDER_TASKS" uid="shell" />
-    <assign-permission name="android.permission.SET_ANIMATION_SCALE" uid="shell" />
-    <assign-permission name="android.permission.SET_PREFERRED_APPLICATIONS" uid="shell" />
-    <assign-permission name="android.permission.WRITE_SETTINGS" uid="shell" />
-    <assign-permission name="android.permission.WRITE_SECURE_SETTINGS" uid="shell" />
-    <assign-permission name="android.permission.BROADCAST_STICKY" uid="shell" />
-    <!-- Development tool permissions granted to the shell. -->
-    <assign-permission name="android.permission.SET_DEBUG_APP" uid="shell" />
-    <assign-permission name="android.permission.SET_PROCESS_LIMIT" uid="shell" />
-    <assign-permission name="android.permission.SET_ALWAYS_FINISH" uid="shell" />
-    <assign-permission name="android.permission.DUMP" uid="shell" />
-    <assign-permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES" uid="shell" />
-    <assign-permission name="android.permission.KILL_BACKGROUND_PROCESSES" uid="shell" />
-    <!-- Internal permissions granted to the shell. -->
-    <assign-permission name="android.permission.FORCE_BACK" uid="shell" />
-    <assign-permission name="android.permission.BATTERY_STATS" uid="shell" />
-    <assign-permission name="android.permission.INTERNAL_SYSTEM_WINDOW" uid="shell" />
-    <assign-permission name="android.permission.INJECT_EVENTS" uid="shell" />
-    <assign-permission name="android.permission.RETRIEVE_WINDOW_CONTENT" uid="shell" />
-    <assign-permission name="android.permission.SET_ACTIVITY_WATCHER" uid="shell" />
-    <assign-permission name="android.permission.READ_INPUT_STATE" uid="shell" />
-    <assign-permission name="android.permission.SET_ORIENTATION" uid="shell" />
-    <assign-permission name="android.permission.INSTALL_PACKAGES" uid="shell" />
-    <assign-permission name="android.permission.CLEAR_APP_USER_DATA" uid="shell" />
-    <assign-permission name="android.permission.DELETE_CACHE_FILES" uid="shell" />
-    <assign-permission name="android.permission.DELETE_PACKAGES" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" />
-    <assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
-    <assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
-    <assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
-    <assign-permission name="android.permission.BACKUP" uid="shell" />
-    <assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
-    <assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" />
-    <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" />
-    <assign-permission name="android.permission.GRANT_REVOKE_PERMISSIONS" uid="shell" />
-    <assign-permission name="android.permission.SET_KEYBOARD_LAYOUT" uid="shell" />
-    <assign-permission name="android.permission.GET_DETAILED_TASKS" uid="shell" />
-    <assign-permission name="android.permission.SET_SCREEN_COMPATIBILITY" uid="shell" />
-    <assign-permission name="android.permission.READ_EXTERNAL_STORAGE" uid="shell" />
-    <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
-    <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" />
-    <assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" />
-    <assign-permission name="android.permission.MANAGE_USERS" uid="shell" />
-    <assign-permission name="android.permission.BLUETOOTH_STACK" uid="shell" />
-    
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
     <assign-permission name="android.permission.ACCESS_DRM" uid="media" />
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 1a7a84e..14f3dd1 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -50,7 +50,7 @@
 </div>
 
 <div class="col-8" style="margin-right:0">
-<img alt=""
+<img style="margin-left:30px" alt=""
 src="//chart.apis.google.com/chart?&cht=p&chs=460x245&chf=bg,s,00000000&chd=t:2.4,8.1,45.4,0.3,29,13.6&chl=Eclair%20%26%20older|Froyo|Gingerbread|Honeycomb|Ice%20Cream%20Sandwich|Jelly%20Bean&chco=c4df9b,6fad0c"
 />
 
diff --git a/docs/html/about/index.jd b/docs/html/about/index.jd
index cf90d04..0b72701 100644
--- a/docs/html/about/index.jd
+++ b/docs/html/about/index.jd
@@ -36,7 +36,7 @@
 driving strong growth in app consumption. Android users download more than 
 1.5 billion apps and games from Google Play each month. </p>
 
-<p>With it's partners, Android is continuously pushing the boundaries of hardware and software
+<p>With its partners, Android is continuously pushing the boundaries of hardware and software
 forward to bring new capabilities to users and developers. For developers, 
 Android innovation lets you build powerful, differentiated applications
 that use the latest mobile technologies.</p>
@@ -65,7 +65,7 @@
 
 <p>Android also gives you tools for creating apps that look great and take
 advantage of the hardware capabilities available on each device. It
-automatically adapts your UI to look it's best on each device, while giving you
+automatically adapts your UI to look its best on each device, while giving you
 as much control as you want over your UI on different device
 types. </p> 
 
diff --git a/docs/html/reference/gcm-lists.js b/docs/html/reference/gcm-lists.js
new file mode 100644
index 0000000..44c6023
--- /dev/null
+++ b/docs/html/reference/gcm-lists.js
@@ -0,0 +1,16 @@
+var GCM_DATA = [
+      { id:0, label:"com.google.android.gcm", link:"reference/com/google/android/gcm/package-summary.html", type:"package" },
+      { id:1, label:"com.google.android.gcm.GCMBaseIntentService", link:"reference/com/google/android/gcm/GCMBaseIntentService.html", type:"class" },
+      { id:2, label:"com.google.android.gcm.GCMBroadcastReceiver", link:"reference/com/google/android/gcm/GCMBroadcastReceiver.html", type:"class" },
+      { id:3, label:"com.google.android.gcm.GCMConstants", link:"reference/com/google/android/gcm/GCMConstants.html", type:"class" },
+      { id:4, label:"com.google.android.gcm.GCMRegistrar", link:"reference/com/google/android/gcm/GCMRegistrar.html", type:"class" },
+      { id:5, label:"com.google.android.gcm.server", link:"reference/com/google/android/gcm/server/package-summary.html", type:"package" },
+      { id:6, label:"com.google.android.gcm.server.Constants", link:"reference/com/google/android/gcm/server/Constants.html", type:"class" },
+      { id:7, label:"com.google.android.gcm.server.InvalidRequestException", link:"reference/com/google/android/gcm/server/InvalidRequestException.html", type:"class" },
+      { id:8, label:"com.google.android.gcm.server.Message", link:"reference/com/google/android/gcm/server/Message.html", type:"class" },
+      { id:9, label:"com.google.android.gcm.server.Message.Builder", link:"reference/com/google/android/gcm/server/Message.Builder.html", type:"class" },
+      { id:10, label:"com.google.android.gcm.server.MulticastResult", link:"reference/com/google/android/gcm/server/MulticastResult.html", type:"class" },
+      { id:11, label:"com.google.android.gcm.server.Result", link:"reference/com/google/android/gcm/server/Result.html", type:"class" },
+      { id:12, label:"com.google.android.gcm.server.Sender", link:"reference/com/google/android/gcm/server/Sender.html", type:"class" }
+
+    ];
diff --git a/docs/html/reference/gms-lists.js b/docs/html/reference/gms-lists.js
new file mode 100644
index 0000000..a5999f7
--- /dev/null
+++ b/docs/html/reference/gms-lists.js
@@ -0,0 +1,93 @@
+var GMS_DATA = [
+      { id:0, label:"com.google.android.gms", link:"reference/com/google/android/gms/package-summary.html", type:"package" },
+      { id:1, label:"com.google.android.gms.R", link:"reference/com/google/android/gms/R.html", type:"class" },
+      { id:2, label:"com.google.android.gms.R.attr", link:"reference/com/google/android/gms/R.attr.html", type:"class" },
+      { id:3, label:"com.google.android.gms.R.id", link:"reference/com/google/android/gms/R.id.html", type:"class" },
+      { id:4, label:"com.google.android.gms.R.string", link:"reference/com/google/android/gms/R.string.html", type:"class" },
+      { id:5, label:"com.google.android.gms.R.styleable", link:"reference/com/google/android/gms/R.styleable.html", type:"class" },
+      { id:6, label:"com.google.android.gms.analytics", link:"reference/com/google/android/gms/analytics/package-summary.html", type:"package" },
+      { id:7, label:"com.google.android.gms.analytics.CampaignTrackingReceiver", link:"reference/com/google/android/gms/analytics/CampaignTrackingReceiver.html", type:"class" },
+      { id:8, label:"com.google.android.gms.analytics.CampaignTrackingService", link:"reference/com/google/android/gms/analytics/CampaignTrackingService.html", type:"class" },
+      { id:9, label:"com.google.android.gms.analytics.EasyTracker", link:"reference/com/google/android/gms/analytics/EasyTracker.html", type:"class" },
+      { id:10, label:"com.google.android.gms.analytics.ExceptionParser", link:"reference/com/google/android/gms/analytics/ExceptionParser.html", type:"class" },
+      { id:11, label:"com.google.android.gms.analytics.GoogleAnalytics", link:"reference/com/google/android/gms/analytics/GoogleAnalytics.html", type:"class" },
+      { id:12, label:"com.google.android.gms.analytics.GoogleAnalytics.AppOptOutCallback", link:"reference/com/google/android/gms/analytics/GoogleAnalytics.AppOptOutCallback.html", type:"class" },
+      { id:13, label:"com.google.android.gms.analytics.ModelFields", link:"reference/com/google/android/gms/analytics/ModelFields.html", type:"class" },
+      { id:14, label:"com.google.android.gms.analytics.StandardExceptionParser", link:"reference/com/google/android/gms/analytics/StandardExceptionParser.html", type:"class" },
+      { id:15, label:"com.google.android.gms.analytics.Tracker", link:"reference/com/google/android/gms/analytics/Tracker.html", type:"class" },
+      { id:16, label:"com.google.android.gms.analytics.Transaction", link:"reference/com/google/android/gms/analytics/Transaction.html", type:"class" },
+      { id:17, label:"com.google.android.gms.analytics.Transaction.Builder", link:"reference/com/google/android/gms/analytics/Transaction.Builder.html", type:"class" },
+      { id:18, label:"com.google.android.gms.analytics.Transaction.Item", link:"reference/com/google/android/gms/analytics/Transaction.Item.html", type:"class" },
+      { id:19, label:"com.google.android.gms.analytics.Transaction.Item.Builder", link:"reference/com/google/android/gms/analytics/Transaction.Item.Builder.html", type:"class" },
+      { id:20, label:"com.google.android.gms.auth", link:"reference/com/google/android/gms/auth/package-summary.html", type:"package" },
+      { id:21, label:"com.google.android.gms.auth.GoogleAuthException", link:"reference/com/google/android/gms/auth/GoogleAuthException.html", type:"class" },
+      { id:22, label:"com.google.android.gms.auth.GoogleAuthUtil", link:"reference/com/google/android/gms/auth/GoogleAuthUtil.html", type:"class" },
+      { id:23, label:"com.google.android.gms.auth.GooglePlayServicesAvailabilityException", link:"reference/com/google/android/gms/auth/GooglePlayServicesAvailabilityException.html", type:"class" },
+      { id:24, label:"com.google.android.gms.auth.UserRecoverableAuthException", link:"reference/com/google/android/gms/auth/UserRecoverableAuthException.html", type:"class" },
+      { id:25, label:"com.google.android.gms.auth.UserRecoverableNotifiedException", link:"reference/com/google/android/gms/auth/UserRecoverableNotifiedException.html", type:"class" },
+      { id:26, label:"com.google.android.gms.common", link:"reference/com/google/android/gms/common/package-summary.html", type:"package" },
+      { id:27, label:"com.google.android.gms.common.AccountPicker", link:"reference/com/google/android/gms/common/AccountPicker.html", type:"class" },
+      { id:28, label:"com.google.android.gms.common.ConnectionResult", link:"reference/com/google/android/gms/common/ConnectionResult.html", type:"class" },
+      { id:29, label:"com.google.android.gms.common.GooglePlayServicesClient", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.html", type:"class" },
+      { id:30, label:"com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html", type:"class" },
+      { id:31, label:"com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener", link:"reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html", type:"class" },
+      { id:32, label:"com.google.android.gms.common.GooglePlayServicesNotAvailableException", link:"reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html", type:"class" },
+      { id:33, label:"com.google.android.gms.common.GooglePlayServicesUtil", link:"reference/com/google/android/gms/common/GooglePlayServicesUtil.html", type:"class" },
+      { id:34, label:"com.google.android.gms.common.Scopes", link:"reference/com/google/android/gms/common/Scopes.html", type:"class" },
+      { id:35, label:"com.google.android.gms.maps", link:"reference/com/google/android/gms/maps/package-summary.html", type:"package" },
+      { id:36, label:"com.google.android.gms.maps.CameraUpdate", link:"reference/com/google/android/gms/maps/CameraUpdate.html", type:"class" },
+      { id:37, label:"com.google.android.gms.maps.CameraUpdateFactory", link:"reference/com/google/android/gms/maps/CameraUpdateFactory.html", type:"class" },
+      { id:38, label:"com.google.android.gms.maps.GoogleMap", link:"reference/com/google/android/gms/maps/GoogleMap.html", type:"class" },
+      { id:39, label:"com.google.android.gms.maps.GoogleMap.CancelableCallback", link:"reference/com/google/android/gms/maps/GoogleMap.CancelableCallback.html", type:"class" },
+      { id:40, label:"com.google.android.gms.maps.GoogleMap.InfoWindowAdapter", link:"reference/com/google/android/gms/maps/GoogleMap.InfoWindowAdapter.html", type:"class" },
+      { id:41, label:"com.google.android.gms.maps.GoogleMap.OnCameraChangeListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnCameraChangeListener.html", type:"class" },
+      { id:42, label:"com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnInfoWindowClickListener.html", type:"class" },
+      { id:43, label:"com.google.android.gms.maps.GoogleMap.OnMapClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html", type:"class" },
+      { id:44, label:"com.google.android.gms.maps.GoogleMap.OnMapLongClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMapLongClickListener.html", type:"class" },
+      { id:45, label:"com.google.android.gms.maps.GoogleMap.OnMarkerClickListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener.html", type:"class" },
+      { id:46, label:"com.google.android.gms.maps.GoogleMap.OnMarkerDragListener", link:"reference/com/google/android/gms/maps/GoogleMap.OnMarkerDragListener.html", type:"class" },
+      { id:47, label:"com.google.android.gms.maps.GoogleMapOptions", link:"reference/com/google/android/gms/maps/GoogleMapOptions.html", type:"class" },
+      { id:48, label:"com.google.android.gms.maps.LocationSource", link:"reference/com/google/android/gms/maps/LocationSource.html", type:"class" },
+      { id:49, label:"com.google.android.gms.maps.LocationSource.OnLocationChangedListener", link:"reference/com/google/android/gms/maps/LocationSource.OnLocationChangedListener.html", type:"class" },
+      { id:50, label:"com.google.android.gms.maps.MapFragment", link:"reference/com/google/android/gms/maps/MapFragment.html", type:"class" },
+      { id:51, label:"com.google.android.gms.maps.MapView", link:"reference/com/google/android/gms/maps/MapView.html", type:"class" },
+      { id:52, label:"com.google.android.gms.maps.MapsInitializer", link:"reference/com/google/android/gms/maps/MapsInitializer.html", type:"class" },
+      { id:53, label:"com.google.android.gms.maps.Projection", link:"reference/com/google/android/gms/maps/Projection.html", type:"class" },
+      { id:54, label:"com.google.android.gms.maps.SupportMapFragment", link:"reference/com/google/android/gms/maps/SupportMapFragment.html", type:"class" },
+      { id:55, label:"com.google.android.gms.maps.UiSettings", link:"reference/com/google/android/gms/maps/UiSettings.html", type:"class" },
+      { id:56, label:"com.google.android.gms.maps.model", link:"reference/com/google/android/gms/maps/model/package-summary.html", type:"package" },
+      { id:57, label:"com.google.android.gms.maps.model.BitmapDescriptor", link:"reference/com/google/android/gms/maps/model/BitmapDescriptor.html", type:"class" },
+      { id:58, label:"com.google.android.gms.maps.model.BitmapDescriptorFactory", link:"reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html", type:"class" },
+      { id:59, label:"com.google.android.gms.maps.model.CameraPosition", link:"reference/com/google/android/gms/maps/model/CameraPosition.html", type:"class" },
+      { id:60, label:"com.google.android.gms.maps.model.CameraPosition.Builder", link:"reference/com/google/android/gms/maps/model/CameraPosition.Builder.html", type:"class" },
+      { id:61, label:"com.google.android.gms.maps.model.GroundOverlay", link:"reference/com/google/android/gms/maps/model/GroundOverlay.html", type:"class" },
+      { id:62, label:"com.google.android.gms.maps.model.GroundOverlayOptions", link:"reference/com/google/android/gms/maps/model/GroundOverlayOptions.html", type:"class" },
+      { id:63, label:"com.google.android.gms.maps.model.LatLng", link:"reference/com/google/android/gms/maps/model/LatLng.html", type:"class" },
+      { id:64, label:"com.google.android.gms.maps.model.LatLngBounds", link:"reference/com/google/android/gms/maps/model/LatLngBounds.html", type:"class" },
+      { id:65, label:"com.google.android.gms.maps.model.LatLngBounds.Builder", link:"reference/com/google/android/gms/maps/model/LatLngBounds.Builder.html", type:"class" },
+      { id:66, label:"com.google.android.gms.maps.model.Marker", link:"reference/com/google/android/gms/maps/model/Marker.html", type:"class" },
+      { id:67, label:"com.google.android.gms.maps.model.MarkerOptions", link:"reference/com/google/android/gms/maps/model/MarkerOptions.html", type:"class" },
+      { id:68, label:"com.google.android.gms.maps.model.Polygon", link:"reference/com/google/android/gms/maps/model/Polygon.html", type:"class" },
+      { id:69, label:"com.google.android.gms.maps.model.PolygonOptions", link:"reference/com/google/android/gms/maps/model/PolygonOptions.html", type:"class" },
+      { id:70, label:"com.google.android.gms.maps.model.Polyline", link:"reference/com/google/android/gms/maps/model/Polyline.html", type:"class" },
+      { id:71, label:"com.google.android.gms.maps.model.PolylineOptions", link:"reference/com/google/android/gms/maps/model/PolylineOptions.html", type:"class" },
+      { id:72, label:"com.google.android.gms.maps.model.RuntimeRemoteException", link:"reference/com/google/android/gms/maps/model/RuntimeRemoteException.html", type:"class" },
+      { id:73, label:"com.google.android.gms.maps.model.Tile", link:"reference/com/google/android/gms/maps/model/Tile.html", type:"class" },
+      { id:74, label:"com.google.android.gms.maps.model.TileOverlay", link:"reference/com/google/android/gms/maps/model/TileOverlay.html", type:"class" },
+      { id:75, label:"com.google.android.gms.maps.model.TileOverlayOptions", link:"reference/com/google/android/gms/maps/model/TileOverlayOptions.html", type:"class" },
+      { id:76, label:"com.google.android.gms.maps.model.TileProvider", link:"reference/com/google/android/gms/maps/model/TileProvider.html", type:"class" },
+      { id:77, label:"com.google.android.gms.maps.model.UrlTileProvider", link:"reference/com/google/android/gms/maps/model/UrlTileProvider.html", type:"class" },
+      { id:78, label:"com.google.android.gms.maps.model.VisibleRegion", link:"reference/com/google/android/gms/maps/model/VisibleRegion.html", type:"class" },
+      { id:79, label:"com.google.android.gms.panorama", link:"reference/com/google/android/gms/panorama/package-summary.html", type:"package" },
+      { id:80, label:"com.google.android.gms.panorama.PanoramaClient", link:"reference/com/google/android/gms/panorama/PanoramaClient.html", type:"class" },
+      { id:81, label:"com.google.android.gms.panorama.PanoramaClient.OnPanoramaInfoLoadedListener", link:"reference/com/google/android/gms/panorama/PanoramaClient.OnPanoramaInfoLoadedListener.html", type:"class" },
+      { id:82, label:"com.google.android.gms.plus", link:"reference/com/google/android/gms/plus/package-summary.html", type:"package" },
+      { id:83, label:"com.google.android.gms.plus.GooglePlusUtil", link:"reference/com/google/android/gms/plus/GooglePlusUtil.html", type:"class" },
+      { id:84, label:"com.google.android.gms.plus.PlusClient", link:"reference/com/google/android/gms/plus/PlusClient.html", type:"class" },
+      { id:85, label:"com.google.android.gms.plus.PlusOneButton", link:"reference/com/google/android/gms/plus/PlusOneButton.html", type:"class" },
+      { id:86, label:"com.google.android.gms.plus.PlusOneButton.OnPlusOneClickListener", link:"reference/com/google/android/gms/plus/PlusOneButton.OnPlusOneClickListener.html", type:"class" },
+      { id:87, label:"com.google.android.gms.plus.PlusShare", link:"reference/com/google/android/gms/plus/PlusShare.html", type:"class" },
+      { id:88, label:"com.google.android.gms.plus.PlusShare.Builder", link:"reference/com/google/android/gms/plus/PlusShare.Builder.html", type:"class" },
+      { id:89, label:"com.google.android.gms.plus.PlusSignInButton", link:"reference/com/google/android/gms/plus/PlusSignInButton.html", type:"class" }
+
+    ];
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index cb9d2ef..dff3a32 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -3,43 +3,44 @@
 header.hide=1
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
-sdk.win32_bundle_download=adt-bundle-windows-x86.zip
-sdk.win32_bundle_bytes=418030942
-sdk.win32_bundle_checksum=ce32861d8f7c93ff6ff6971bd99d228e
-
-sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=418155677
-sdk.win64_bundle_checksum=f09aa4557bd1dc2703fde95dcdd6b92e
-
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=383216991
-sdk.mac64_bundle_checksum=ea6c074ee30c426c503dab5c225a5076
 
 sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
-sdk.linux32_bundle_bytes=411205048
-sdk.linux32_bundle_checksum=e64594cd339b8d9a400b9d16c616b3c3
+sdk.linux32_bundle_bytes=418614971
+sdk.linux32_bundle_checksum=24506708af221a887326c2a9ca9625dc
 
 sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=411478695
-sdk.linux64_bundle_checksum=582bfc9083ff4cbcfacc8223bd8c3be1
+sdk.linux64_bundle_bytes=418889835
+sdk.linux64_bundle_checksum=464c1fbe92ea293d6b2292c27af5066a
+
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
+sdk.mac64_bundle_bytes=390649300
+sdk.mac64_bundle_checksum=f557bc61a4bff466633037839771bffb
+
+sdk.win32_bundle_download=adt-bundle-windows-x86.zip
+sdk.win32_bundle_bytes=425429957
+sdk.win32_bundle_checksum=cca97f12904774385a57d542e70a490f
+
+sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
+sdk.win64_bundle_bytes=425553759
+sdk.win64_bundle_checksum=c51679f4517e1c3ddefa1e662bbf17f6
 
 
 
-sdk.win_installer=installer_r21.0.1-windows.exe
-sdk.win_installer_bytes=76520869
-sdk.win_installer_checksum=e2012262471a2583d4a559b15fcf45ff
+sdk.linux_download=android-sdk_r21.1.0-linux.tgz
+sdk.linux_bytes=91617112
+sdk.linux_checksum=3369a439240cf3dbe165d6b4173900a8
 
-sdk.win_download=android-sdk_r21.0.1-windows.zip
-sdk.win_bytes=99107847
-sdk.win_checksum=613568d774c3bf25c5d24db16601af83
+sdk.mac_download=android-sdk_r21.1.0-macosx.zip
+sdk.mac_bytes=66077080
+sdk.mac_checksum=49903cf79e1f8e3fde54a95bd3666385
 
-sdk.mac_download=android-sdk_r21.0.1-macosx.zip
-sdk.mac_bytes=65804128
-sdk.mac_checksum=30401c43a014cd5d6ec9d0c62854a1d9
+sdk.win_download=android-sdk_r21.1.0-windows.zip
+sdk.win_bytes=99360755
+sdk.win_checksum=dbece8859da9b66a1e8e7cd47b1e647e
 
-sdk.linux_download=android-sdk_r21.0.1-linux.tgz
-sdk.linux_bytes=91394975
-sdk.linux_checksum=eaa5a8d76d692d1d027f2bbcee019644
+sdk.win_installer=installer_r21.1.0-windows.exe
+sdk.win_installer_bytes=77767013
+sdk.win_installer_checksum=594d8ff8e349db9e783a5f2229561353
 
 
 
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 804030b..d956af2 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
 adt.zip.version=21.0.1
-adt.zip.download=ADT-21.0.1.zip
-adt.zip.bytes=13569302
-adt.zip.checksum=acfb01bf3fd1240f1fc21488c3dd16bf
+adt.zip.download=ADT-21.1.0.zip
+adt.zip.bytes=13564671
+adt.zip.checksum=f1ae183891229784bb9c33bcc9c5ef1e
 
 @jd:body
 
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index 61cd08a..cf7b63f 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -111,7 +111,17 @@
   </li>
 </ol>
 
-<p>When plugged in over USB, can verify that your device is connected by executing <code>adb
+
+<p class="note"><strong>Note:</strong> When you connect a device running Android 4.2.2 or higher
+to your computer, the system shows a dialog asking whether to accept an RSA key that allows
+debugging through this computer. This security mechanism protects user devices because it ensures
+that USB debugging and other adb commands cannot be executed unless you're able to unlock the
+device and acknowledge the dialog. This requires that you have adb version 1.0.31 (available with
+SDK Platform-tools r16.0.1 and higher) in order to debug on a device running Android 4.2.2 or
+higher.</p>
+
+
+<p>When plugged in over USB, you can verify that your device is connected by executing <code>adb
 devices</code> from your SDK {@code platform-tools/} directory. If connected,
 you'll see the device name listed as a "device."</p>
 
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index e0ee0e6..c8afca5 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
Binary files differ
diff --git a/docs/html/tools/publishing/app-signing.jd b/docs/html/tools/publishing/app-signing.jd
index ac45242..608780e 100644
--- a/docs/html/tools/publishing/app-signing.jd
+++ b/docs/html/tools/publishing/app-signing.jd
@@ -96,8 +96,7 @@
 you don't have a private key, you can use the Keytool utility to create one for you. When you
 compile your application in release mode, the build tools use your private key along with the
 Jarsigner utility to sign your application's <code>.apk</code> file. Because the certificate and
-private key you use are your own, you will have to provide the password for the keystore and key
-alias.</p>
+private key you use are your own, you must provide the password for the keystore and key alias.</p>
 
 <p>The debug signing process happens automatically when you run or debug your application using
 Eclipse with the ADT plugin. Debug signing also happens automatically when you use the Ant build
@@ -117,13 +116,13 @@
 
 <ul>
 <li>Application upgrade &ndash; As you release updates to your application, you
-will want to continue to sign the updates with the same certificate or set of
-certificates, if you want users to upgrade seamlessly to the new version. When
+must continue to sign the updates with the same certificate or set of certificates,
+if you want users to be able to upgrade seamlessly to the new version. When
 the system is installing an update to an application, it compares the
 certificate(s) in the new version with those in the existing version. If the
 certificates match exactly, including both the certificate data and order, then
 the system allows the update. If you sign the new version without using matching
-certificates, you will also need to assign a different package name to the
+certificates, you must also assign a different package name to the
 application &mdash; in this case, the user installs the new version as a
 completely new application. </li>
 
@@ -314,6 +313,13 @@
 particular, when you are generating your key, you should select strong passwords
 for both the keystore and key.</p>
 
+<p class="warning"><strong>Warning:</strong> Keep the keystore file you generate with Keytool
+in a safe, secure place. You must use the same key to sign future versions of your application. If
+you republish your app with a new key, Google Play will consider it a new app. For more information
+on settings that must remain constant over the life of your app, see the Android Developer Blog post
+<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
+That Cannot Change</a>.</p>
+
 <table>
 <tr>
 <th>Keytool Option</th>
@@ -597,6 +603,10 @@
 sign and distribute applications under your identity that attack other
 applications or the system itself, or corrupt or steal user data. </p>
 
+<p>Your private key is required for signing all future versions of your application. If you lose or
+misplace your key, you will not be able to publish updates to your existing application. You cannot
+regenerate a previously generated key.</p>
+
 <p>Your reputation as a developer entity depends on your securing your private
 key properly, at all times, until the key is expired. Here are some tips for
 keeping your key secure: </p>
@@ -612,7 +622,9 @@
 options at the command line. </li>
 <li>Do not give or lend anyone your private key, and do not let unauthorized
 persons know your keystore and key passwords.</li>
+<li>Keep the keystore file containing your private key that you <a href="#cert">generate with the
+Keytool</a> in a safe, secure place.</li>
 </ul>
 
 <p>In general, if you follow common-sense precautions when generating, using,
-and storing your key, it will remain secure. </p>
\ No newline at end of file
+and storing your key, it will remain secure. </p>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 243683c..4adb7b2 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,63 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 21.1.0</a> <em>(February 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required for ADT 21.1.0.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.1.0.</li>
+      <li>ADT 21.1.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
+      Tools r21.1.0</a>. If you haven't already installed SDK Tools r21.1.0 into your SDK, use the
+      Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Added new <a href="{@docRoot}tools/projects/templates.html">code templates</a> for
+        notifications, blank fragments and list fragments.</li>
+      <li>Added support for resource rename refactoring. Renaming a resource XML file, drawable
+        icon, an {@code R.} field name or ID in the layout editor invokes a refactoring routine
+        to update all resource references.</li>
+      <li>Added more than 15 new Lint checks, including checks for overriding older APIs, XML
+        resource problems, graphic asset issues and manifest tags.
+      <li>Updated XML Editor to respond to refactoring shortcut keys such as <strong>Refactor
+        &gt; Rename</strong>.</li>
+      <li>Updated XML Editor to improve double click handling.</li>
+      <li>Added code completion improvements for custom views, theme references and class
+        references. For example, code completion in a {@code &lt;fragment android:name=””&gt;} tag
+        now suggests completion with a list of fragment classes. Similarly, code completion in the
+        manifest now offers implementations suitable for the given tag.</li>
+      <li>Updated the <strong>Project Import</strong> dialog so that it shows a table for all
+        imported projects where you can edit the name of the imported project.</li>
+      <li>Added support for layout aliases in the Layout Editor.</li>
+    </ul>
+  </dd>
+
+  <dt>Bug fixes:</dt>
+  <dd>
+    <ul>
+      <li>Fixed issued with refactoring support for renaming and moving classes and packages.
+      </li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 21.0.1</a> <em>(December 2012)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 9349a4e..a5b7eee 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,41 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 21.1.0</a> <em>(February 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 16 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1.0 is
+          designed for use with ADT 21.1.0 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.1.0.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+    </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Improved error reporting in {@code dx} when dex merging fails in the build
+          system.</li>
+        <li>Added more than 15 new Lint checks, including checks for overriding older APIs, XML
+          resource problems, graphic asset issues and manifest tags.</li>
+        <li>Added new aapt feature to compile resources.</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 21.0.1</a> <em>(December 2012)</em>
   </p>
 
@@ -40,7 +75,7 @@
         <li>Android SDK Platform-tools revision 16 or later.</li>
         <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.0.1 is
           designed for use with ADT 21.0.1 and later. If you haven't already, update your
-        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.0.</li>
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.1.</li>
         <li>If you are developing outside Eclipse, you must have
           <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
     </ul>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 483d11a..9684f20 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -62,18 +62,6 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private int mSurfaceFormat;
 
-    /**
-     * Flag for drawTextRun indicating left-to-right run direction.
-     * @hide
-     */
-    public static final int DIRECTION_LTR = 0;
-    
-    /**
-     * Flag for drawTextRun indicating right-to-left run direction.
-     * @hide
-     */
-    public static final int DIRECTION_RTL = 1;
-
     // Maximum bitmap size as defined in Skia's native code
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
@@ -1341,8 +1329,7 @@
             (text.length - index - count)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mNativePaint);
     }
 
     /**
@@ -1355,8 +1342,7 @@
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(String text, float x, float y, Paint paint) {
-        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mNativePaint);
     }
 
     /**
@@ -1374,8 +1360,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mNativePaint);
     }
 
     /**
@@ -1394,16 +1379,14 @@
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
-            native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
-                            paint.mBidiFlags, paint.mNativePaint);
+            native_drawText(mNativeCanvas, text.toString(), start, end, x, y, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
                                                      paint);
         } else {
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
-            native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
-                    paint.mBidiFlags, paint.mNativePaint);
+            native_drawText(mNativeCanvas, buf, 0, end - start, x, y, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1424,13 +1407,11 @@
      *         + count.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
-     * @param dir the run direction, either {@link #DIRECTION_LTR} or
-     *         {@link #DIRECTION_RTL}.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1441,12 +1422,9 @@
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown dir: " + dir);
-        }
 
         native_drawTextRun(mNativeCanvas, text, index, count,
-                contextIndex, contextCount, x, y, dir, paint.mNativePaint);
+                contextIndex, contextCount, x, y, paint.mNativePaint);
     }
 
     /**
@@ -1462,12 +1440,11 @@
      *            position can be used for shaping context.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
-     * @param dir the run direction, either 0 for LTR or 1 for RTL.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1479,22 +1456,20 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int flags = dir == 0 ? 0 : 1;
-
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, flags, paint.mNativePaint);
+                    contextStart, contextEnd, x, y, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    contextStart, contextEnd, x, y, flags, paint);
+                    contextStart, contextEnd, x, y, paint);
         } else {
             int contextLen = contextEnd - contextStart;
             int len = end - start;
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
-                    0, contextLen, x, y, flags, paint.mNativePaint);
+                    0, contextLen, x, y, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1560,8 +1535,7 @@
             throw new ArrayIndexOutOfBoundsException();
         }
         native_drawTextOnPath(mNativeCanvas, text, index, count,
-                              path.ni(), hOffset, vOffset,
-                              paint.mBidiFlags, paint.mNativePaint);
+                              path.ni(), hOffset, vOffset, paint.mNativePaint);
     }
 
     /**
@@ -1580,7 +1554,7 @@
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
         if (text.length() > 0) {
             native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mNativePaint);
         }
     }
 
@@ -1737,18 +1711,18 @@
     
     private static native void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
-                                               float y, int flags, int paint);
+                                               float y, int paint);
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
-                                               float y, int flags, int paint);
+                                               float y, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, int paint);
+            float x, float y, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int flags, int paint);
+            float x, float y, int paint);
 
     private static native void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
@@ -1761,13 +1735,13 @@
                                                      char[] text, int index,
                                                      int count, int path,
                                                      float hOffset,
-                                                     float vOffset, int bidiFlags,
+                                                     float vOffset,
                                                      int paint);
     private static native void native_drawTextOnPath(int nativeCanvas,
                                                      String text, int path,
                                                      float hOffset, 
                                                      float vOffset, 
-                                                     int flags, int paint);
+                                                     int paint);
     private static native void native_drawPicture(int nativeCanvas,
                                                   int nativePicture);
     private static native void finalizer(int nativeCanvas);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3285e51..3a83d12 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -69,11 +69,6 @@
      */
     public int shadowColor;
 
-    /**
-     * @hide
-     */
-    public  int         mBidiFlags = BIDI_DEFAULT_LTR;
-    
     static final Style[] sStyleArray = {
         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
     };
@@ -120,74 +115,6 @@
     public static final int HINTING_ON = 0x1;
 
     /**
-     * Bidi flag to set LTR paragraph direction.
-     * 
-     * @hide
-     */
-    public static final int BIDI_LTR = 0x0;
-
-    /**
-     * Bidi flag to set RTL paragraph direction.
-     * 
-     * @hide
-     */
-    public static final int BIDI_RTL = 0x1;
-
-    /**
-     * Bidi flag to detect paragraph direction via heuristics, defaulting to
-     * LTR.
-     * 
-     * @hide
-     */
-    public static final int BIDI_DEFAULT_LTR = 0x2;
-
-    /**
-     * Bidi flag to detect paragraph direction via heuristics, defaulting to
-     * RTL.
-     * 
-     * @hide
-     */
-    public static final int BIDI_DEFAULT_RTL = 0x3;
-
-    /**
-     * Bidi flag to override direction to all LTR (ignore bidi).
-     * 
-     * @hide
-     */
-    public static final int BIDI_FORCE_LTR = 0x4;
-
-    /**
-     * Bidi flag to override direction to all RTL (ignore bidi).
-     * 
-     * @hide
-     */
-    public static final int BIDI_FORCE_RTL = 0x5;
-
-    /**
-     * Maximum Bidi flag value.
-     * @hide
-     */
-    private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
-
-    /**
-     * Mask for bidi flags.
-     * @hide
-     */
-    private static final int BIDI_FLAG_MASK = 0x7;
-
-    /**
-     * Flag for getTextRunAdvances indicating left-to-right run direction.
-     * @hide
-     */
-    public static final int DIRECTION_LTR = 0;
-
-    /**
-     * Flag for getTextRunAdvances indicating right-to-left run direction.
-     * @hide
-     */
-    public static final int DIRECTION_RTL = 1;
-
-    /**
      * Option for getTextRunCursor to compute the valid cursor after
      * offset or the limit of the context, whichever is less.
      * @hide
@@ -395,7 +322,6 @@
         shadowRadius = 0;
         shadowColor = 0;
 
-        mBidiFlags = BIDI_DEFAULT_LTR;
         setTextLocale(Locale.getDefault());
     }
     
@@ -435,7 +361,6 @@
         shadowRadius = paint.shadowRadius;
         shadowColor = paint.shadowColor;
 
-        mBidiFlags = paint.mBidiFlags;
         mLocale = paint.mLocale;
     }
 
@@ -452,29 +377,6 @@
     }
 
     /**
-     * Return the bidi flags on the paint.
-     * 
-     * @return the bidi flags on the paint
-     * @hide
-     */
-    public int getBidiFlags() {
-        return mBidiFlags;
-    }
-
-    /**
-     * Set the bidi flags on the paint.
-     * @hide
-     */
-    public void setBidiFlags(int flags) {
-        // only flag value is the 3-bit BIDI control setting
-        flags &= BIDI_FLAG_MASK;
-        if (flags > BIDI_MAX_FLAG_VALUE) {
-            throw new IllegalArgumentException("unknown bidi flag: " + flags);
-        }
-        mBidiFlags = flags;
-    }
-
-    /**
      * Return the paint's flags. Use the Flag enum to test flag values.
      * 
      * @return the paint's flags (see enums ending in _Flag for bit masks)
@@ -1666,76 +1568,19 @@
     }
 
     /**
-     * Return the glyph Ids for the characters in the string.
-     *
-     * @param text   The text to measure
-     * @param start  The index of the first char to to measure
-     * @param end    The end of the text slice to measure
-     * @param contextStart the index of the first character to use for shaping context,
-     * must be <= start
-     * @param contextEnd the index past the last character to use for shaping context,
-     * must be >= end
-     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
-     * or {@link #DIRECTION_RTL}
-     * @param glyphs array to receive the glyph Ids of the characters.
-     *               Must be at least a large as the text.
-     * @return       the number of glyphs in the returned array
-     *
-     * @hide
-     *
-     * Used only for BiDi / RTL Tests
-     */
-    public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
-            int flags, char[] glyphs) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
-        if ((start | end | contextStart | contextEnd | (end - start)
-                | (start - contextStart) | (contextEnd - end) | (text.length() - end)
-                | (text.length() - contextEnd)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (end - start > glyphs.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
-                flags, glyphs);
-    }
-
-    /**
      * Convenience overload that takes a char array instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, int flags, float[] advances,
+            int contextIndex, int contextCount, float[] advances,
             int advancesIndex) {
-        return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags,
-                advances, advancesIndex, 0 /* use Harfbuzz*/);
-    }
-
-    /**
-     * Convenience overload that takes a char array instead of a
-     * String.
-     *
-     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int)
-     * @hide
-     */
-    public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, int flags, float[] advances,
-            int advancesIndex, int reserved) {
 
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
         if ((index | count | contextIndex | contextCount | advancesIndex
                 | (index - contextIndex) | (contextCount - count)
                 | ((contextIndex + contextCount) - (index + count))
@@ -1750,13 +1595,13 @@
         }
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, chars, index, count,
-                    contextIndex, contextCount, flags, advances, advancesIndex, reserved);
+                    contextIndex, contextCount, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
-                contextIndex, contextCount, flags, advances, advancesIndex, reserved);
+                contextIndex, contextCount, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1771,26 +1616,12 @@
      * Convenience overload that takes a CharSequence instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, int flags, float[] advances,
+            int contextStart, int contextEnd, float[] advances,
             int advancesIndex) {
-        return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
-                advances, advancesIndex, 0 /* use Harfbuzz */);
-    }
-
-    /**
-     * Convenience overload that takes a CharSequence instead of a
-     * String.
-     *
-     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
-     * @hide
-     */
-    public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, int flags, float[] advances,
-            int advancesIndex, int reserved) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
@@ -1805,16 +1636,16 @@
 
         if (text instanceof String) {
             return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+                    contextStart, contextEnd, advances, advancesIndex);
         }
         if (text instanceof SpannedString ||
             text instanceof SpannableString) {
             return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+                    contextStart, contextEnd, advances, advancesIndex);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex, this);
+                    contextStart, contextEnd, advances, advancesIndex, this);
         }
         if (text.length() == 0 || end == start) {
             return 0f;
@@ -1825,7 +1656,7 @@
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
         float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, flags, advances, advancesIndex, reserved);
+                0, contextLen, advances, advancesIndex);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1862,8 +1693,6 @@
      * must be <= start
      * @param contextEnd the index past the last character to use for shaping context,
      * must be >= end
-     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
-     * or {@link #DIRECTION_RTL}
      * @param advances array to receive the advances, must have room for all advances,
      * can be null if only total advance is needed
      * @param advancesIndex the position in advances at which to put the
@@ -1873,63 +1702,11 @@
      * @hide
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, int flags, float[] advances, int advancesIndex) {
-        return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
-                advances, advancesIndex, 0 /* use Harfbuzz*/);
-    }
-
-    /**
-     * Returns the total advance width for the characters in the run
-     * between start and end, and if advances is not null, the advance
-     * assigned to each of these characters (java chars).
-     *
-     * <p>The trailing surrogate in a valid surrogate pair is assigned
-     * an advance of 0.  Thus the number of returned advances is
-     * always equal to count, not to the number of unicode codepoints
-     * represented by the run.
-     *
-     * <p>In the case of conjuncts or combining marks, the total
-     * advance is assigned to the first logical character, and the
-     * following characters are assigned an advance of 0.
-     *
-     * <p>This generates the sum of the advances of glyphs for
-     * characters in a reordered cluster as the width of the first
-     * logical character in the cluster, and 0 for the widths of all
-     * other characters in the cluster.  In effect, such clusters are
-     * treated like conjuncts.
-     *
-     * <p>The shaping bounds limit the amount of context available
-     * outside start and end that can be used for shaping analysis.
-     * These bounds typically reflect changes in bidi level or font
-     * metrics across which shaping does not occur.
-     *
-     * @param text the text to measure. Cannot be null.
-     * @param start the index of the first character to measure
-     * @param end the index past the last character to measure
-     * @param contextStart the index of the first character to use for shaping context,
-     * must be <= start
-     * @param contextEnd the index past the last character to use for shaping context,
-     * must be >= end
-     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
-     * or {@link #DIRECTION_RTL}
-     * @param advances array to receive the advances, must have room for all advances,
-     * can be null if only total advance is needed
-     * @param advancesIndex the position in advances at which to put the
-     * advance corresponding to the character at start
-     * @param reserved int reserved value
-     * @return the total advance
-     *
-     * @hide
-     */
-    public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) {
+            int contextEnd, float[] advances, int advancesIndex) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                 | (start - contextStart) | (contextEnd - end)
                 | (text.length() - contextEnd)
@@ -1944,13 +1721,13 @@
 
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, text, start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+                    contextStart, contextEnd, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
-                contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+                contextStart, contextEnd, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1979,7 +1756,6 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextLength the length of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1988,7 +1764,7 @@
      * @hide
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
-            int flags, int offset, int cursorOpt) {
+            int offset, int cursorOpt) {
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -1998,7 +1774,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextLength, flags, offset, cursorOpt);
+                contextStart, contextLength, offset, cursorOpt);
     }
 
     /**
@@ -2019,7 +1795,6 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2028,22 +1803,22 @@
      * @hide
      */
     public int getTextRunCursor(CharSequence text, int contextStart,
-           int contextEnd, int flags, int offset, int cursorOpt) {
+           int contextEnd, int offset, int cursorOpt) {
 
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             return getTextRunCursor(text.toString(), contextStart, contextEnd,
-                    flags, offset, cursorOpt);
+                    offset, cursorOpt);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunCursor(
-                    contextStart, contextEnd, flags, offset, cursorOpt, this);
+                    contextStart, contextEnd, offset, cursorOpt, this);
         }
 
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
+        int result = getTextRunCursor(buf, 0, contextLen, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -2066,7 +1841,6 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2084,7 +1858,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextEnd, flags, offset, cursorOpt);
+                contextStart, contextEnd, offset, cursorOpt);
     }
 
     /**
@@ -2105,7 +1879,7 @@
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, 
+        native_getTextPath(mNativePaint, text, index, count, x, y,
                 path.ni());
     }
 
@@ -2127,7 +1901,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, 
+        native_getTextPath(mNativePaint, text, start, end, x, y,
                 path.ni());
     }
     
@@ -2219,26 +1993,22 @@
     private static native int native_getTextWidths(int native_object,
                             String text, int start, int end, float[] widths);
 
-    private static native int native_getTextGlyphs(int native_object,
-            String text, int start, int end, int contextStart, int contextEnd,
-            int flags, char[] glyphs);
-
     private static native float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            int flags, float[] advances, int advancesIndex, int reserved);
+            float[] advances, int advancesIndex);
     private static native float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex, int reserved);
+            float[] advances, int advancesIndex);
 
     private native int native_getTextRunCursor(int native_object, char[] text,
-            int contextStart, int contextLength, int flags, int offset, int cursorOpt);
+            int contextStart, int contextLength, int offset, int cursorOpt);
     private native int native_getTextRunCursor(int native_object, String text,
-            int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
+            int contextStart, int contextEnd, int offset, int cursorOpt);
 
-    private static native void native_getTextPath(int native_object, int bidiFlags,
-                char[] text, int index, int count, float x, float y, int path);
-    private static native void native_getTextPath(int native_object, int bidiFlags,
-                String text, int start, int end, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, char[] text,
+            int index, int count, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, String text,
+            int start, int end, float x, float y, int path);
     private static native void nativeGetStringBounds(int nativePaint,
                                 String text, int start, int end, Rect bounds);
     private static native void nativeGetCharArrayBounds(int nativePaint,
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 5f0844a..1c83c51 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -488,7 +488,11 @@
      */
     public void copyFromUnchecked(int[] d) {
         mRS.validate();
-        copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        }
     }
     /**
      * Copy an allocation from an array.  This variant is not type
@@ -499,7 +503,11 @@
      */
     public void copyFromUnchecked(short[] d) {
         mRS.validate();
-        copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        }
     }
     /**
      * Copy an allocation from an array.  This variant is not type
@@ -510,7 +518,11 @@
      */
     public void copyFromUnchecked(byte[] d) {
         mRS.validate();
-        copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        }
     }
     /**
      * Copy an allocation from an array.  This variant is not type
@@ -521,7 +533,11 @@
      */
     public void copyFromUnchecked(float[] d) {
         mRS.validate();
-        copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFromUnchecked(0, mCurrentCount, d);
+        }
     }
 
     /**
@@ -533,7 +549,11 @@
      */
     public void copyFrom(int[] d) {
         mRS.validate();
-        copy1DRangeFrom(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFrom(0, mCurrentCount, d);
+        }
     }
 
     /**
@@ -545,7 +565,11 @@
      */
     public void copyFrom(short[] d) {
         mRS.validate();
-        copy1DRangeFrom(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFrom(0, mCurrentCount, d);
+        }
     }
 
     /**
@@ -557,7 +581,11 @@
      */
     public void copyFrom(byte[] d) {
         mRS.validate();
-        copy1DRangeFrom(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFrom(0, mCurrentCount, d);
+        }
     }
 
     /**
@@ -569,7 +597,11 @@
      */
     public void copyFrom(float[] d) {
         mRS.validate();
-        copy1DRangeFrom(0, mCurrentCount, d);
+        if (mCurrentDimY > 0) {
+            copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
+        } else {
+            copy1DRangeFrom(0, mCurrentCount, d);
+        }
     }
 
     /**
@@ -827,6 +859,35 @@
         }
     }
 
+    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, byte[] data) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+                              w, h, data, data.length);
+    }
+
+    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, short[] data) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+                              w, h, data, data.length * 2);
+    }
+
+    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, int[] data) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+                              w, h, data, data.length * 4);
+    }
+
+    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, float[] data) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+                              w, h, data, data.length * 4);
+    }
+
+
     /**
      * Copy a rectangular region from the array into the allocation.
      * The incoming array is assumed to be tightly packed.
@@ -838,31 +899,23 @@
      * @param data to be placed into the allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length);
+        validateIsInt8();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 2);
+        validateIsInt16();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 4);
+        validateIsInt32();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
     }
 
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 4);
+        validateIsFloat32();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data);
     }
 
     /**
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index a215a57..0a7e882 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +29,12 @@
         mData = new byte[len];
     }
 
+    public FieldPacker(byte[] data) {
+        mPos = 0;
+        mLen = data.length;
+        mData = data;
+    }
+
     public void align(int v) {
         if ((v <= 0) || ((v & (v - 1)) != 0)) {
             throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index b53ba0d..b405588 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -171,6 +171,11 @@
             throw new RSIllegalArgumentException(
                 "At least one of ain or aout is required to be non-null.");
         }
+
+        if (sc == null) {
+            forEach(slot, ain, aout, v);
+            return;
+        }
         int in_id = 0;
         if (ain != null) {
             in_id = ain.getID(mRS);
diff --git a/icu4j/java/android/icu/text/ArabicShaping.java b/icu4j/java/android/icu/text/ArabicShaping.java
deleted file mode 100644
index 13e2175..0000000
--- a/icu4j/java/android/icu/text/ArabicShaping.java
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
-*******************************************************************************
-*   Copyright (C) 2001-2009, International Business Machines
-*   Corporation and others.  All Rights Reserved.
-*******************************************************************************
-*/
-
-/*
- * Ported with minor modifications from ICU4J 4.2's
- * com.ibm.icu.text.ArabicShaping class.
- */
-
-package android.icu.text;
-
-
-/**
- * Shape Arabic text on a character basis.
- *
- * <p>ArabicShaping performs basic operations for "shaping" Arabic text. It is most
- * useful for use with legacy data formats and legacy display technology
- * (simple terminals). All operations are performed on Unicode characters.</p>
- *
- * <p>Text-based shaping means that some character code points in the text are
- * replaced by others depending on the context. It transforms one kind of text
- * into another. In comparison, modern displays for Arabic text select
- * appropriate, context-dependent font glyphs for each text element, which means
- * that they transform text into a glyph vector.</p>
- *
- * <p>Text transformations are necessary when modern display technology is not
- * available or when text needs to be transformed to or from legacy formats that
- * use "shaped" characters. Since the Arabic script is cursive, connecting
- * adjacent letters to each other, computers select images for each letter based
- * on the surrounding letters. This usually results in four images per Arabic
- * letter: initial, middle, final, and isolated forms. In Unicode, on the other
- * hand, letters are normally stored abstract, and a display system is expected
- * to select the necessary glyphs. (This makes searching and other text
- * processing easier because the same letter has only one code.) It is possible
- * to mimic this with text transformations because there are characters in
- * Unicode that are rendered as letters with a specific shape
- * (or cursive connectivity). They were included for interoperability with
- * legacy systems and codepages, and for unsophisticated display systems.</p>
- *
- * <p>A second kind of text transformations is supported for Arabic digits:
- * For compatibility with legacy codepages that only include European digits,
- * it is possible to replace one set of digits by another, changing the
- * character code points. These operations can be performed for either
- * Arabic-Indic Digits (U+0660...U+0669) or Eastern (Extended) Arabic-Indic
- * digits (U+06f0...U+06f9).</p>
- *
- * <p>Some replacements may result in more or fewer characters (code points).
- * By default, this means that the destination buffer may receive text with a
- * length different from the source length. Some legacy systems rely on the
- * length of the text to be constant. They expect extra spaces to be added
- * or consumed either next to the affected character or at the end of the
- * text.</p>
- * @stable ICU 2.0
- *
- * @hide
- */
-public class ArabicShaping {
-    private final int options;
-    private boolean isLogical; // convenience
-    private boolean spacesRelativeToTextBeginEnd;
-    private char tailChar;
-
-    public static final ArabicShaping SHAPER = new ArabicShaping(
-            ArabicShaping.TEXT_DIRECTION_LOGICAL |
-            ArabicShaping.LENGTH_FIXED_SPACES_NEAR |
-            ArabicShaping.LETTERS_SHAPE |
-            ArabicShaping.DIGITS_NOOP);
-
-    /**
-     * Convert a range of text in the source array, putting the result
-     * into a range of text in the destination array, and return the number
-     * of characters written.
-     *
-     * @param source An array containing the input text
-     * @param sourceStart The start of the range of text to convert
-     * @param sourceLength The length of the range of text to convert
-     * @param dest The destination array that will receive the result.
-     *   It may be <code>NULL</code> only if  <code>destSize</code> is 0.
-     * @param destStart The start of the range of the destination buffer to use.
-     * @param destSize The size (capacity) of the destination buffer.
-     *   If <code>destSize</code> is 0, then no output is produced,
-     *   but the necessary buffer size is returned ("preflighting").  This
-     *   does not validate the text against the options, for example,
-     *   if letters are being unshaped, and spaces are being consumed
-     *   following lamalef, this will not detect a lamalef without a
-     *   corresponding space.  An error will be thrown when the actual
-     *   conversion is attempted.
-     * @return The number of chars written to the destination buffer.
-     *   If an error occurs, then no output was written, or it may be
-     *   incomplete.
-     * @throws ArabicShapingException if the text cannot be converted according to the options.
-     * @stable ICU 2.0
-     */
-    public int shape(char[] source, int sourceStart, int sourceLength,
-                     char[] dest, int destStart, int destSize) throws ArabicShapingException {
-        if (source == null) {
-            throw new IllegalArgumentException("source can not be null");
-        }
-        if (sourceStart < 0 || sourceLength < 0 || sourceStart + sourceLength > source.length) {
-            throw new IllegalArgumentException("bad source start (" + sourceStart +
-                                               ") or length (" + sourceLength +
-                                               ") for buffer of length " + source.length);
-        }
-        if (dest == null && destSize != 0) {
-            throw new IllegalArgumentException("null dest requires destSize == 0");
-        }
-        if ((destSize != 0) &&
-            (destStart < 0 || destSize < 0 || destStart + destSize > dest.length)) {
-            throw new IllegalArgumentException("bad dest start (" + destStart +
-                                               ") or size (" + destSize +
-                                               ") for buffer of length " + dest.length);
-        }
-        /* Validate input options */
-        if ( ((options&TASHKEEL_MASK) > 0) &&
-             !(((options & TASHKEEL_MASK)==TASHKEEL_BEGIN)  ||
-               ((options & TASHKEEL_MASK)==TASHKEEL_END )   ||
-               ((options & TASHKEEL_MASK)==TASHKEEL_RESIZE )||
-               ((options & TASHKEEL_MASK)==TASHKEEL_REPLACE_BY_TATWEEL)) ){
-            throw new IllegalArgumentException("Wrong Tashkeel argument");
-        }
-
-       ///CLOVER:OFF
-       //According to Steven Loomis, the code is unreachable when you OR all the constants within the if statements
-       if(((options&LAMALEF_MASK) > 0)&&
-              !(((options & LAMALEF_MASK)==LAMALEF_BEGIN)  ||
-                ((options & LAMALEF_MASK)==LAMALEF_END )   ||
-                ((options & LAMALEF_MASK)==LAMALEF_RESIZE )||
-                 ((options & LAMALEF_MASK)==LAMALEF_AUTO)  ||
-                 ((options & LAMALEF_MASK)==LAMALEF_NEAR))){
-           throw new IllegalArgumentException("Wrong Lam Alef argument");
-       }
-       ///CLOVER:ON
-
-       /* Validate Tashkeel (Tashkeel replacement options should be enabled in shaping mode only)*/
-       if(((options&TASHKEEL_MASK) > 0) && (options&LETTERS_MASK) == LETTERS_UNSHAPE) {
-            throw new IllegalArgumentException("Tashkeel replacement should not be enabled in deshaping mode ");
-       }
-       return internalShape(source, sourceStart, sourceLength, dest, destStart, destSize);
-    }
-
-    /**
-     * Convert a range of text in place.  This may only be used if the Length option
-     * does not grow or shrink the text.
-     *
-     * @param source An array containing the input text
-     * @param start The start of the range of text to convert
-     * @param length The length of the range of text to convert
-     * @throws ArabicShapingException if the text cannot be converted according to the options.
-     * @stable ICU 2.0
-     */
-    public void shape(char[] source, int start, int length) throws ArabicShapingException {
-        if ((options & LAMALEF_MASK) == LAMALEF_RESIZE) {
-            throw new ArabicShapingException("Cannot shape in place with length option resize.");
-        }
-        shape(source, start, length, source, start, length);
-    }
-
-    /**
-     * Convert a string, returning the new string.
-     *
-     * @param text the string to convert
-     * @return the converted string
-     * @throws ArabicShapingException if the string cannot be converted according to the options.
-     * @stable ICU 2.0
-     */
-    public String shape(String text) throws ArabicShapingException {
-        char[] src = text.toCharArray();
-        char[] dest = src;
-        if (((options & LAMALEF_MASK) == LAMALEF_RESIZE) &&
-            ((options & LETTERS_MASK) == LETTERS_UNSHAPE)) {
-
-            dest = new char[src.length * 2]; // max
-        }
-        int len = shape(src, 0, src.length, dest, 0, dest.length);
-
-        return new String(dest, 0, len);
-    }
-
-    /**
-     * Construct ArabicShaping using the options flags.
-     * The flags are as follows:<br>
-     * 'LENGTH' flags control whether the text can change size, and if not,
-     * how to maintain the size of the text when LamAlef ligatures are
-     * formed or broken.<br>
-     * 'TEXT_DIRECTION' flags control whether the text is read and written
-     * in visual order or in logical order.<br>
-     * 'LETTERS_SHAPE' flags control whether conversion is to or from
-     * presentation forms.<br>
-     * 'DIGITS' flags control whether digits are shaped, and whether from
-     * European to Arabic-Indic or vice-versa.<br>
-     * 'DIGIT_TYPE' flags control whether standard or extended Arabic-Indic
-     * digits are used when performing digit conversion.
-     * @stable ICU 2.0
-     */
-    public ArabicShaping(int options) {
-        this.options = options;
-        if ((options & DIGITS_MASK) > 0x80) {
-            throw new IllegalArgumentException("bad DIGITS options");
-        }
-
-        isLogical = ( (options & TEXT_DIRECTION_MASK) == TEXT_DIRECTION_LOGICAL );
-        /* Validate options */
-        spacesRelativeToTextBeginEnd = ( (options & SPACES_RELATIVE_TO_TEXT_MASK) == SPACES_RELATIVE_TO_TEXT_BEGIN_END );
-        if ( (options&SHAPE_TAIL_TYPE_MASK) == SHAPE_TAIL_NEW_UNICODE){
-            tailChar = NEW_TAIL_CHAR;
-        } else {
-            tailChar = OLD_TAIL_CHAR;
-        }
-    }
-
-    /* Seen Tail options */
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping mode: The SEEN family character will expand into two characters using space near
-     *               the SEEN family character(i.e. the space after the character).
-     *               if there are no spaces found, ArabicShapingException will be thrown
-     *
-     * De-shaping mode: Any Seen character followed by Tail character will be
-     *                  replaced by one cell Seen and a space will replace the Tail.
-     * Affects: Seen options
-     */
-    public static final int SEEN_TWOCELL_NEAR = 0x200000;
-
-    /** Bit mask for Seen memory options. */
-    public static final int SEEN_MASK = 0x700000;
-
-    /* YehHamza options */
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping mode: The YEHHAMZA character will expand into two characters using space near it
-     *              (i.e. the space after the character)
-     *               if there are no spaces found, ArabicShapingException will be thrown
-     *
-     * De-shaping mode: Any Yeh (final or isolated) character followed by Hamza character will be
-     *                  replaced by one cell YehHamza and space will replace the Hamza.
-     * Affects: YehHamza options
-     */
-    public static final int YEHHAMZA_TWOCELL_NEAR  = 0x1000000;
-
-
-    /** Bit mask for YehHamza memory options. */
-    public static final int YEHHAMZA_MASK = 0x3800000;
-
-    /* New Tashkeel options */
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping mode: Tashkeel characters will be replaced by spaces.
-     *               Spaces will be placed at beginning of the buffer
-     *
-     * De-shaping mode: N/A
-     * Affects: Tashkeel options
-     */
-    public static final int TASHKEEL_BEGIN = 0x40000;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping mode: Tashkeel characters will be replaced by spaces.
-     *               Spaces will be placed at end of the buffer
-     *
-     * De-shaping mode: N/A
-     * Affects: Tashkeel options
-     */
-    public static final int TASHKEEL_END = 0x60000;
-
-    /**
-     * Memory option: allow the result to have a different length than the source.
-     * Shaping mode: Tashkeel characters will be removed, buffer length will shrink.
-     * De-shaping mode: N/A
-     *
-     * Affects: Tashkeel options
-     */
-    public static final int TASHKEEL_RESIZE = 0x80000;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping mode: Tashkeel characters will be replaced by Tatweel if it is connected to adjacent
-     *               characters (i.e. shaped on Tatweel) or replaced by space if it is not connected.
-     *
-     * De-shaping mode: N/A
-     * Affects: YehHamza options
-     */
-    public static final int TASHKEEL_REPLACE_BY_TATWEEL = 0xC0000;
-
-    /** Bit mask for Tashkeel replacement with Space or Tatweel memory options. */
-    public static final int TASHKEEL_MASK  = 0xE0000;
-
-    /* Space location Control options */
-    /**
-     * This option effects the meaning of BEGIN and END options. if this option is not used the default
-     * for BEGIN and END will be as following:
-     * The Default (for both Visual LTR, Visual RTL and Logical Text)
-     *           1. BEGIN always refers to the start address of physical memory.
-     *           2. END always refers to the end address of physical memory.
-     *
-     * If this option is used it will swap the meaning of BEGIN and END only for Visual LTR text.
-     *
-     * The affect on BEGIN and END Memory Options will be as following:
-     *    A. BEGIN For Visual LTR text: This will be the beginning (right side) of the visual text
-     *       (corresponding to the physical memory address end, same as END in default behavior)
-     *    B. BEGIN For Logical text: Same as BEGIN in default behavior.
-     *    C. END For Visual LTR text: This will be the end (left side) of the visual text. (corresponding to
-     *      the physical memory address beginning, same as BEGIN in default behavior)
-     *    D. END For Logical text: Same as END in default behavior.
-     * Affects: All LamAlef BEGIN, END and AUTO options.
-     */
-    public static final int SPACES_RELATIVE_TO_TEXT_BEGIN_END = 0x4000000;
-
-    /** Bit mask for swapping BEGIN and END for Visual LTR text */
-    public static final int SPACES_RELATIVE_TO_TEXT_MASK = 0x4000000;
-
-    /**
-     * If this option is used, shaping will use the new Unicode code point for TAIL (i.e. 0xFE73).
-     * If this option is not specified (Default), old unofficial Unicode TAIL code point is used (i.e. 0x200B)
-     * De-shaping will not use this option as it will always search for both the new Unicode code point for the
-     * TAIL (i.e. 0xFE73) or the old unofficial Unicode TAIL code point (i.e. 0x200B) and de-shape the
-     * Seen-Family letter accordingly.
-     *
-     * Shaping Mode: Only shaping.
-     * De-shaping Mode: N/A.
-     * Affects: All Seen options
-     */
-    public static final int SHAPE_TAIL_NEW_UNICODE = 0x8000000;
-
-    /** Bit mask for new Unicode Tail option */
-    public static final int SHAPE_TAIL_TYPE_MASK = 0x8000000;
-
-    /**
-     * Memory option: allow the result to have a different length than the source.
-     * @stable ICU 2.0
-     */
-    public static final int LENGTH_GROW_SHRINK = 0;
-
-    /**
-     * Memory option: allow the result to have a different length than the source.
-     * Affects: LamAlef options
-     * This option is an alias to LENGTH_GROW_SHRINK
-     */
-    public static final int LAMALEF_RESIZE   = 0;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces next to modified characters.
-     * @stable ICU 2.0
-     */
-    public static final int LENGTH_FIXED_SPACES_NEAR = 1;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces next to modified characters.
-     * Affects: LamAlef options
-     * This option is an alias to LENGTH_FIXED_SPACES_NEAR
-     */
-    public static final int LAMALEF_NEAR = 1 ;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces at the end of the text.
-     * @stable ICU 2.0
-     */
-    public static final int LENGTH_FIXED_SPACES_AT_END = 2;
-
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces at the end of the text.
-     * Affects: LamAlef options
-     * This option is an alias to LENGTH_FIXED_SPACES_AT_END
-     */
-    public static final int LAMALEF_END = 2;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces at the beginning of the text.
-     * @stable ICU 2.0
-     */
-    public static final int LENGTH_FIXED_SPACES_AT_BEGINNING = 3;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * If more room is necessary, then try to consume spaces at the beginning of the text.
-     * Affects: LamAlef options
-     * This option is an alias to LENGTH_FIXED_SPACES_AT_BEGINNING
-     */
-    public static final int LAMALEF_BEGIN = 3;
-
-    /**
-     * Memory option: the result must have the same length as the source.
-     * Shaping Mode: For each LAMALEF character found, expand LAMALEF using space at end.
-     *               If there is no space at end, use spaces at beginning of the buffer. If there
-     *               is no space at beginning of the buffer, use spaces at the near (i.e. the space
-     *               after the LAMALEF character).
-     *
-     * Deshaping Mode: Perform the same function as the flag equals LAMALEF_END.
-     * Affects: LamAlef options
-     */
-    public static final int LAMALEF_AUTO  = 0x10000;
-
-    /**
-     * Bit mask for memory options.
-     * @stable ICU 2.0
-     */
-    public static final int LENGTH_MASK = 0x10003;
-
-    /** Bit mask for LamAlef memory options. */
-
-    public static final int LAMALEF_MASK  = 0x10003;
-
-    /**
-     * Direction indicator: the source is in logical (keyboard) order.
-     * @stable ICU 2.0
-     */
-    public static final int TEXT_DIRECTION_LOGICAL = 0;
-
-    /**
-     * Direction indicator:the source is in visual RTL order,
-     * the rightmost displayed character stored first.
-     * This option is an alias to U_SHAPE_TEXT_DIRECTION_LOGICAL
-     */
-    public static final int TEXT_DIRECTION_VISUAL_RTL = 0;
-
-    /**
-     * Direction indicator: the source is in visual (display) order, that is,
-     * the leftmost displayed character is stored first.
-     * @stable ICU 2.0
-     */
-    public static final int TEXT_DIRECTION_VISUAL_LTR = 4;
-
-    /**
-     * Bit mask for direction indicators.
-     * @stable ICU 2.0
-     */
-    public static final int TEXT_DIRECTION_MASK = 4;
-
-
-    /**
-     * Letter shaping option: do not perform letter shaping.
-     * @stable ICU 2.0
-     */
-    public static final int LETTERS_NOOP = 0;
-
-    /**
-     * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
-     * by shaped ones in the U+FE70 (Presentation Forms B) block. Performs Lam-Alef ligature
-     * substitution.
-     * @stable ICU 2.0
-     */
-    public static final int LETTERS_SHAPE = 8;
-
-    /**
-     * Letter shaping option: replace shaped letter characters in the U+FE70 (Presentation Forms B) block
-     * by normative ones in the U+0600 (Arabic) block.  Converts Lam-Alef ligatures to pairs of Lam and
-     * Alef characters, consuming spaces if required.
-     * @stable ICU 2.0
-     */
-    public static final int LETTERS_UNSHAPE = 0x10;
-
-    /**
-     * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
-     * except for the TASHKEEL characters at U+064B...U+0652, by shaped ones in the U+Fe70
-     * (Presentation Forms B) block.  The TASHKEEL characters will always be converted to
-     * the isolated forms rather than to their correct shape.
-     * @stable ICU 2.0
-     */
-    public static final int LETTERS_SHAPE_TASHKEEL_ISOLATED = 0x18;
-
-    /**
-     * Bit mask for letter shaping options.
-     * @stable ICU 2.0
-     */
-    public static final int LETTERS_MASK = 0x18;
-
-
-    /**
-     * Digit shaping option: do not perform digit shaping.
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_NOOP = 0;
-
-    /**
-     * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits.
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_EN2AN = 0x20;
-
-    /**
-     * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039).
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_AN2EN = 0x40;
-
-    /**
-     * Digit shaping option:
-     * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
-     * if the most recent strongly directional character
-     * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
-     * The initial state at the start of the text is assumed to be not an Arabic,
-     * letter, so European digits at the start of the text will not change.
-     * Compare to DIGITS_ALEN2AN_INIT_AL.
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_EN2AN_INIT_LR = 0x60;
-
-    /**
-     * Digit shaping option:
-     * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
-     * if the most recent strongly directional character
-     * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
-     * The initial state at the start of the text is assumed to be an Arabic,
-     * letter, so European digits at the start of the text will change.
-     * Compare to DIGITS_ALEN2AN_INT_LR.
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_EN2AN_INIT_AL = 0x80;
-
-    /** Not a valid option value. */
-    //private static final int DIGITS_RESERVED = 0xa0;
-
-    /**
-     * Bit mask for digit shaping options.
-     * @stable ICU 2.0
-     */
-    public static final int DIGITS_MASK = 0xe0;
-
-    /**
-     * Digit type option: Use Arabic-Indic digits (U+0660...U+0669).
-     * @stable ICU 2.0
-     */
-    public static final int DIGIT_TYPE_AN = 0;
-
-    /**
-     * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9).
-     * @stable ICU 2.0
-     */
-    public static final int DIGIT_TYPE_AN_EXTENDED = 0x100;
-
-    /**
-     * Bit mask for digit type options.
-     * @stable ICU 2.0
-     */
-    public static final int DIGIT_TYPE_MASK = 0x0100; // 0x3f00?
-
-    /**
-     * some constants
-     */
-    private static final char HAMZAFE_CHAR       = '\ufe80';
-    private static final char HAMZA06_CHAR       = '\u0621';
-    private static final char YEH_HAMZA_CHAR     = '\u0626';
-    private static final char YEH_HAMZAFE_CHAR   = '\uFE89';
-    private static final char LAMALEF_SPACE_SUB  = '\uffff';
-    private static final char TASHKEEL_SPACE_SUB = '\ufffe';
-    private static final char LAM_CHAR      = '\u0644';
-    private static final char SPACE_CHAR    = '\u0020';
-    private static final char SPACE_CHAR_FOR_LAMALEF = '\ufeff'; // XXX: tweak for TextLine use
-    private static final char SHADDA_CHAR   = '\uFE7C';
-    private static final char TATWEEL_CHAR  = '\u0640';
-    private static final char SHADDA_TATWEEL_CHAR = '\uFE7D';
-    private static final char NEW_TAIL_CHAR = '\uFE73';
-    private static final char OLD_TAIL_CHAR = '\u200B';
-    private static final int SHAPE_MODE      = 0;
-    private static final int DESHAPE_MODE    = 1;
-
-    /**
-     * @stable ICU 2.0
-     */
-    public boolean equals(Object rhs) {
-        return rhs != null &&
-            rhs.getClass() == ArabicShaping.class &&
-            options == ((ArabicShaping)rhs).options;
-    }
-
-    /**
-     * @stable ICU 2.0
-     */
-     ///CLOVER:OFF
-    public int hashCode() {
-        return options;
-    }
-
-    /**
-     * @stable ICU 2.0
-     */
-    public String toString() {
-        StringBuffer buf = new StringBuffer(super.toString());
-        buf.append('[');
-
-        switch (options & LAMALEF_MASK) {
-        case LAMALEF_RESIZE: buf.append("LamAlef resize"); break;
-        case LAMALEF_NEAR: buf.append("LamAlef spaces at near"); break;
-        case LAMALEF_BEGIN: buf.append("LamAlef spaces at begin"); break;
-        case LAMALEF_END: buf.append("LamAlef spaces at end"); break;
-        case LAMALEF_AUTO: buf.append("lamAlef auto"); break;
-        }
-        switch (options & TEXT_DIRECTION_MASK) {
-        case TEXT_DIRECTION_LOGICAL: buf.append(", logical"); break;
-        case TEXT_DIRECTION_VISUAL_LTR: buf.append(", visual"); break;
-        }
-        switch (options & LETTERS_MASK) {
-        case LETTERS_NOOP: buf.append(", no letter shaping"); break;
-        case LETTERS_SHAPE: buf.append(", shape letters"); break;
-        case LETTERS_SHAPE_TASHKEEL_ISOLATED: buf.append(", shape letters tashkeel isolated"); break;
-        case LETTERS_UNSHAPE: buf.append(", unshape letters"); break;
-        }
-        switch (options & SEEN_MASK) {
-        case SEEN_TWOCELL_NEAR: buf.append(", Seen at near"); break;
-        }
-        switch (options & YEHHAMZA_MASK) {
-        case YEHHAMZA_TWOCELL_NEAR: buf.append(", Yeh Hamza at near"); break;
-        }
-        switch (options & TASHKEEL_MASK) {
-        case TASHKEEL_BEGIN: buf.append(", Tashkeel at begin"); break;
-        case TASHKEEL_END: buf.append(", Tashkeel at end"); break;
-        case TASHKEEL_REPLACE_BY_TATWEEL: buf.append(", Tashkeel replace with tatweel"); break;
-        case TASHKEEL_RESIZE: buf.append(", Tashkeel resize"); break;
-        }
-
-        switch (options & DIGITS_MASK) {
-        case DIGITS_NOOP: buf.append(", no digit shaping"); break;
-        case DIGITS_EN2AN: buf.append(", shape digits to AN"); break;
-        case DIGITS_AN2EN: buf.append(", shape digits to EN"); break;
-        case DIGITS_EN2AN_INIT_LR: buf.append(", shape digits to AN contextually: default EN"); break;
-        case DIGITS_EN2AN_INIT_AL: buf.append(", shape digits to AN contextually: default AL"); break;
-        }
-        switch (options & DIGIT_TYPE_MASK) {
-        case DIGIT_TYPE_AN: buf.append(", standard Arabic-Indic digits"); break;
-        case DIGIT_TYPE_AN_EXTENDED: buf.append(", extended Arabic-Indic digits"); break;
-        }
-        buf.append("]");
-
-        return buf.toString();
-    }
-    ///CLOVER:ON
-
-    //
-    // ported api
-    //
-
-    private static final int IRRELEVANT = 4;
-    private static final int LAMTYPE = 16;
-    private static final int ALEFTYPE = 32;
-
-    private static final int LINKR = 1;
-    private static final int LINKL = 2;
-    private static final int LINK_MASK = 3;
-
-    private static final int irrelevantPos[] = {
-        0x0, 0x2, 0x4, 0x6, 0x8, 0xA, 0xC, 0xE
-    };
-
-/*
-    private static final char convertLamAlef[] =  {
-        '\u0622', // FEF5
-        '\u0622', // FEF6
-        '\u0623', // FEF7
-        '\u0623', // FEF8
-        '\u0625', // FEF9
-        '\u0625', // FEFA
-        '\u0627', // FEFB
-        '\u0627'  // FEFC
-    };
-*/
-
-    private static final int tailFamilyIsolatedFinal[] = {
-        /* FEB1 */ 1,
-        /* FEB2 */ 1,
-        /* FEB3 */ 0,
-        /* FEB4 */ 0,
-        /* FEB5 */ 1,
-        /* FEB6 */ 1,
-        /* FEB7 */ 0,
-        /* FEB8 */ 0,
-        /* FEB9 */ 1,
-        /* FEBA */ 1,
-        /* FEBB */ 0,
-        /* FEBC */ 0,
-        /* FEBD */ 1,
-        /* FEBE */ 1
-    };
-
-    private static final int tashkeelMedial[] = {
-        /* FE70 */ 0,
-        /* FE71 */ 1,
-        /* FE72 */ 0,
-        /* FE73 */ 0,
-        /* FE74 */ 0,
-        /* FE75 */ 0,
-        /* FE76 */ 0,
-        /* FE77 */ 1,
-        /* FE78 */ 0,
-        /* FE79 */ 1,
-        /* FE7A */ 0,
-        /* FE7B */ 1,
-        /* FE7C */ 0,
-        /* FE7D */ 1,
-        /* FE7E */ 0,
-        /* FE7F */ 1
-    };
-
-    private static final char yehHamzaToYeh[] =
-    {
-    /* isolated*/ 0xFEEF,
-    /* final   */ 0xFEF0
-    };
-
-    private static final char convertNormalizedLamAlef[] = {
-        '\u0622', // 065C
-        '\u0623', // 065D
-        '\u0625', // 065E
-        '\u0627', // 065F
-    };
-
-    private static final int[] araLink = {
-        1           + 32 + 256 * 0x11,  /*0x0622*/
-        1           + 32 + 256 * 0x13,  /*0x0623*/
-        1                + 256 * 0x15,  /*0x0624*/
-        1           + 32 + 256 * 0x17,  /*0x0625*/
-        1 + 2            + 256 * 0x19,  /*0x0626*/
-        1           + 32 + 256 * 0x1D,  /*0x0627*/
-        1 + 2            + 256 * 0x1F,  /*0x0628*/
-        1                + 256 * 0x23,  /*0x0629*/
-        1 + 2            + 256 * 0x25,  /*0x062A*/
-        1 + 2            + 256 * 0x29,  /*0x062B*/
-        1 + 2            + 256 * 0x2D,  /*0x062C*/
-        1 + 2            + 256 * 0x31,  /*0x062D*/
-        1 + 2            + 256 * 0x35,  /*0x062E*/
-        1                + 256 * 0x39,  /*0x062F*/
-        1                + 256 * 0x3B,  /*0x0630*/
-        1                + 256 * 0x3D,  /*0x0631*/
-        1                + 256 * 0x3F,  /*0x0632*/
-        1 + 2            + 256 * 0x41,  /*0x0633*/
-        1 + 2            + 256 * 0x45,  /*0x0634*/
-        1 + 2            + 256 * 0x49,  /*0x0635*/
-        1 + 2            + 256 * 0x4D,  /*0x0636*/
-        1 + 2            + 256 * 0x51,  /*0x0637*/
-        1 + 2            + 256 * 0x55,  /*0x0638*/
-        1 + 2            + 256 * 0x59,  /*0x0639*/
-        1 + 2            + 256 * 0x5D,  /*0x063A*/
-        0, 0, 0, 0, 0,                  /*0x063B-0x063F*/
-        1 + 2,                          /*0x0640*/
-        1 + 2            + 256 * 0x61,  /*0x0641*/
-        1 + 2            + 256 * 0x65,  /*0x0642*/
-        1 + 2            + 256 * 0x69,  /*0x0643*/
-        1 + 2       + 16 + 256 * 0x6D,  /*0x0644*/
-        1 + 2            + 256 * 0x71,  /*0x0645*/
-        1 + 2            + 256 * 0x75,  /*0x0646*/
-        1 + 2            + 256 * 0x79,  /*0x0647*/
-        1                + 256 * 0x7D,  /*0x0648*/
-        1                + 256 * 0x7F,  /*0x0649*/
-        1 + 2            + 256 * 0x81,  /*0x064A*/
-        4, 4, 4, 4,                     /*0x064B-0x064E*/
-        4, 4, 4, 4,                     /*0x064F-0x0652*/
-        4, 4, 4, 0, 0,                  /*0x0653-0x0657*/
-        0, 0, 0, 0,                     /*0x0658-0x065B*/
-        1                + 256 * 0x85,  /*0x065C*/
-        1                + 256 * 0x87,  /*0x065D*/
-        1                + 256 * 0x89,  /*0x065E*/
-        1                + 256 * 0x8B,  /*0x065F*/
-        0, 0, 0, 0, 0,                  /*0x0660-0x0664*/
-        0, 0, 0, 0, 0,                  /*0x0665-0x0669*/
-        0, 0, 0, 0, 0, 0,               /*0x066A-0x066F*/
-        4,                              /*0x0670*/
-        0,                              /*0x0671*/
-        1           + 32,               /*0x0672*/
-        1           + 32,               /*0x0673*/
-        0,                              /*0x0674*/
-        1           + 32,               /*0x0675*/
-        1, 1,                           /*0x0676-0x0677*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x0678-0x067D*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x067E-0x0683*/
-        1+2, 1+2, 1+2, 1+2,             /*0x0684-0x0687*/
-        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*0x0688-0x0691*/
-        1, 1, 1, 1, 1, 1, 1, 1,         /*0x0692-0x0699*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x069A-0x06A3*/
-        1+2, 1+2, 1+2, 1+2,             /*0x069A-0x06A3*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06A4-0x06AD*/
-        1+2, 1+2, 1+2, 1+2,             /*0x06A4-0x06AD*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06AE-0x06B7*/
-        1+2, 1+2, 1+2, 1+2,             /*0x06AE-0x06B7*/
-        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06B8-0x06BF*/
-        1+2, 1+2,                       /*0x06B8-0x06BF*/
-        1,                              /*0x06C0*/
-        1+2,                            /*0x06C1*/
-        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*0x06C2-0x06CB*/
-        1+2,                            /*0x06CC*/
-        1,                              /*0x06CD*/
-        1+2, 1+2, 1+2, 1+2,             /*0x06CE-0x06D1*/
-        1, 1                            /*0x06D2-0x06D3*/
-    };
-
-    private static final int[] presLink = {
-        1 + 2,                        /*0xFE70*/
-        1 + 2,                        /*0xFE71*/
-        1 + 2, 0, 1+ 2, 0, 1+ 2,      /*0xFE72-0xFE76*/
-        1 + 2,                        /*0xFE77*/
-        1+ 2, 1 + 2, 1+2, 1 + 2,      /*0xFE78-0xFE81*/
-        1+ 2, 1 + 2, 1+2, 1 + 2,      /*0xFE82-0xFE85*/
-        0, 0 + 32, 1 + 32, 0 + 32,    /*0xFE86-0xFE89*/
-        1 + 32, 0, 1,  0 + 32,        /*0xFE8A-0xFE8D*/
-        1 + 32, 0, 2,  1 + 2,         /*0xFE8E-0xFE91*/
-        1, 0 + 32, 1 + 32, 0,         /*0xFE92-0xFE95*/
-        2, 1 + 2, 1, 0,               /*0xFE96-0xFE99*/
-        1, 0, 2, 1 + 2,               /*0xFE9A-0xFE9D*/
-        1, 0, 2, 1 + 2,               /*0xFE9E-0xFEA1*/
-        1, 0, 2, 1 + 2,               /*0xFEA2-0xFEA5*/
-        1, 0, 2, 1 + 2,               /*0xFEA6-0xFEA9*/
-        1, 0, 2, 1 + 2,               /*0xFEAA-0xFEAD*/
-        1, 0, 1, 0,                   /*0xFEAE-0xFEB1*/
-        1, 0, 1, 0,                   /*0xFEB2-0xFEB5*/
-        1, 0, 2, 1+2,                 /*0xFEB6-0xFEB9*/
-        1, 0, 2, 1+2,                 /*0xFEBA-0xFEBD*/
-        1, 0, 2, 1+2,                 /*0xFEBE-0xFEC1*/
-        1, 0, 2, 1+2,                 /*0xFEC2-0xFEC5*/
-        1, 0, 2, 1+2,                 /*0xFEC6-0xFEC9*/
-        1, 0, 2, 1+2,                 /*0xFECA-0xFECD*/
-        1, 0, 2, 1+2,                 /*0xFECE-0xFED1*/
-        1, 0, 2, 1+2,                 /*0xFED2-0xFED5*/
-        1, 0, 2, 1+2,                 /*0xFED6-0xFED9*/
-        1, 0, 2, 1+2,                 /*0xFEDA-0xFEDD*/
-        1, 0, 2, 1+2,                 /*0xFEDE-0xFEE1*/
-        1, 0 + 16, 2 + 16, 1 + 2 +16, /*0xFEE2-0xFEE5*/
-        1 + 16, 0, 2, 1+2,            /*0xFEE6-0xFEE9*/
-        1, 0, 2, 1+2,                 /*0xFEEA-0xFEED*/
-        1, 0, 2, 1+2,                 /*0xFEEE-0xFEF1*/
-        1, 0, 1, 0,                   /*0xFEF2-0xFEF5*/
-        1, 0, 2, 1+2,                 /*0xFEF6-0xFEF9*/
-        1, 0, 1, 0,                   /*0xFEFA-0xFEFD*/
-        1, 0, 1, 0,
-        1
-    };
-
-    private static int[] convertFEto06 = {
-        /***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
-        /*FE7*/   0x64B, 0x64B, 0x64C, 0x64C, 0x64D, 0x64D, 0x64E, 0x64E, 0x64F, 0x64F, 0x650, 0x650, 0x651, 0x651, 0x652, 0x652,
-        /*FE8*/   0x621, 0x622, 0x622, 0x623, 0x623, 0x624, 0x624, 0x625, 0x625, 0x626, 0x626, 0x626, 0x626, 0x627, 0x627, 0x628,
-        /*FE9*/   0x628, 0x628, 0x628, 0x629, 0x629, 0x62A, 0x62A, 0x62A, 0x62A, 0x62B, 0x62B, 0x62B, 0x62B, 0x62C, 0x62C, 0x62C,
-        /*FEA*/   0x62C, 0x62D, 0x62D, 0x62D, 0x62D, 0x62E, 0x62E, 0x62E, 0x62E, 0x62F, 0x62F, 0x630, 0x630, 0x631, 0x631, 0x632,
-        /*FEB*/   0x632, 0x633, 0x633, 0x633, 0x633, 0x634, 0x634, 0x634, 0x634, 0x635, 0x635, 0x635, 0x635, 0x636, 0x636, 0x636,
-        /*FEC*/   0x636, 0x637, 0x637, 0x637, 0x637, 0x638, 0x638, 0x638, 0x638, 0x639, 0x639, 0x639, 0x639, 0x63A, 0x63A, 0x63A,
-        /*FED*/   0x63A, 0x641, 0x641, 0x641, 0x641, 0x642, 0x642, 0x642, 0x642, 0x643, 0x643, 0x643, 0x643, 0x644, 0x644, 0x644,
-        /*FEE*/   0x644, 0x645, 0x645, 0x645, 0x645, 0x646, 0x646, 0x646, 0x646, 0x647, 0x647, 0x647, 0x647, 0x648, 0x648, 0x649,
-        /*FEF*/   0x649, 0x64A, 0x64A, 0x64A, 0x64A, 0x65C, 0x65C, 0x65D, 0x65D, 0x65E, 0x65E, 0x65F, 0x65F
-    };
-
-    private static final int shapeTable[][][] = {
-        { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,1} },
-        { {0,0,2,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} },
-        { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,3} },
-        { {0,0,1,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} }
-    };
-
-    /*
-     * This function shapes European digits to Arabic-Indic digits
-     * in-place, writing over the input characters.  Data is in visual
-     * order.
-     */
-    private void shapeToArabicDigitsWithContext(char[] dest,
-                                                int start,
-                                                int length,
-                                                char digitBase,
-                                                boolean lastStrongWasAL) {
-        digitBase -= '0'; // move common adjustment out of loop
-
-        for(int i = start + length; --i >= start;) {
-            char ch = dest[i];
-            switch (Character.getDirectionality(ch)) {
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
-                lastStrongWasAL = false;
-                break;
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-                lastStrongWasAL = true;
-                break;
-            case Character.DIRECTIONALITY_EUROPEAN_NUMBER:
-                if (lastStrongWasAL && ch <= '\u0039') {
-                    dest[i] = (char)(ch + digitBase);
-                }
-                break;
-            default:
-                break;
-            }
-        }
-    }
-
-    /*
-     * Name    : invertBuffer
-     * Function: This function inverts the buffer, it's used
-     *           in case the user specifies the buffer to be
-     *           TEXT_DIRECTION_LOGICAL
-     */
-    private static void invertBuffer(char[] buffer,
-                                     int start,
-                                     int length) {
-
-        for(int i = start, j = start + length - 1; i < j; i++, --j) {
-            char temp = buffer[i];
-            buffer[i] = buffer[j];
-            buffer[j] = temp;
-        }
-    }
-
-    /*
-     * Name    : changeLamAlef
-     * Function: Converts the Alef characters into an equivalent
-     *           LamAlef location in the 0x06xx Range, this is an
-     *           intermediate stage in the operation of the program
-     *           later it'll be converted into the 0xFExx LamAlefs
-     *           in the shaping function.
-     */
-    private static char changeLamAlef(char ch) {
-        switch(ch) {
-        case '\u0622': return '\u065C';
-        case '\u0623': return '\u065D';
-        case '\u0625': return '\u065E';
-        case '\u0627': return '\u065F';
-        default:  return '\u0000'; // not a lamalef
-        }
-    }
-
-    /*
-     * Name    : specialChar
-     * Function: Special Arabic characters need special handling in the shapeUnicode
-     *           function, this function returns 1 or 2 for these special characters
-     */
-    private static int specialChar(char ch) {
-        if ((ch > '\u0621' && ch < '\u0626') ||
-            (ch == '\u0627') ||
-            (ch > '\u062E' && ch < '\u0633') ||
-            (ch > '\u0647' && ch < '\u064A') ||
-            (ch == '\u0629')) {
-            return 1;
-        } else if (ch >= '\u064B' && ch<= '\u0652') {
-            return 2;
-        } else if (ch >= 0x0653 && ch <= 0x0655 ||
-                   ch == 0x0670 ||
-                   ch >= 0xFE70 && ch <= 0xFE7F) {
-            return 3;
-        } else {
-            return 0;
-        }
-    }
-
-    /*
-     * Name    : getLink
-     * Function: Resolves the link between the characters as
-     *           Arabic characters have four forms :
-     *           Isolated, Initial, Middle and Final Form
-     */
-    private static int getLink(char ch) {
-        if (ch >= '\u0622' && ch <= '\u06D3') {
-            return araLink[ch - '\u0622'];
-        } else if (ch == '\u200D') {
-            return 3;
-        } else if (ch >= '\u206D' && ch <= '\u206F') {
-            return 4;
-        } else if (ch >= '\uFE70' && ch <= '\uFEFC') {
-            return presLink[ch - '\uFE70'];
-        } else {
-            return 0;
-        }
-    }
-
-    /*
-     * Name    : countSpaces
-     * Function: Counts the number of spaces
-     *           at each end of the logical buffer
-     */
-    private static int countSpacesLeft(char[] dest,
-                                       int start,
-                                       int count) {
-        for (int i = start, e = start + count; i < e; ++i) {
-            if (dest[i] != SPACE_CHAR) {
-                return i - start;
-            }
-        }
-        return count;
-    }
-
-    private static int countSpacesRight(char[] dest,
-                                        int start,
-                                        int count) {
-
-        for (int i = start + count; --i >= start;) {
-            if (dest[i] != SPACE_CHAR) {
-                return start + count - 1 - i;
-            }
-        }
-        return count;
-    }
-
-    /*
-     * Name    : isTashkeelChar
-     * Function: Returns true for Tashkeel characters else return false
-     */
-    private static boolean isTashkeelChar(char ch) {
-        return ( ch >='\u064B' && ch <= '\u0652' );
-    }
-
-    /*
-     *Name     : isSeenTailFamilyChar
-     *Function : returns 1 if the character is a seen family isolated character
-     *           in the FE range otherwise returns 0
-     */
-
-    private static int isSeenTailFamilyChar(char ch) {
-        if (ch >= 0xfeb1 && ch < 0xfebf){
-             return tailFamilyIsolatedFinal [ch - 0xFEB1];
-        } else {
-             return 0;
-        }
-    }
-
-     /* Name     : isSeenFamilyChar
-      * Function : returns 1 if the character is a seen family character in the Unicode
-      *            06 range otherwise returns 0
-     */
-
-    private static int isSeenFamilyChar(char  ch){
-        if (ch >= 0x633 && ch <= 0x636){
-            return 1;
-        }else {
-            return 0;
-        }
-    }
-
-    /*
-     *Name     : isTailChar
-     *Function : returns true if the character matches one of the tail characters
-     *           (0xfe73 or 0x200b) otherwise returns false
-     */
-
-    private static boolean isTailChar(char ch) {
-        if(ch == OLD_TAIL_CHAR || ch == NEW_TAIL_CHAR){
-                return true;
-        }else{
-                return false;
-        }
-    }
-
-    /*
-     *Name     : isAlefMaksouraChar
-     *Function : returns true if the character is a Alef Maksoura Final or isolated
-     *           otherwise returns false
-     */
-    private static boolean isAlefMaksouraChar(char ch) {
-        return ( (ch == 0xFEEF) || ( ch == 0xFEF0) || (ch == 0x0649));
-    }
-
-    /*
-     * Name     : isYehHamzaChar
-     * Function : returns true if the character is a yehHamza isolated or yehhamza
-     *            final is found otherwise returns false
-     */
-    private static boolean isYehHamzaChar(char ch) {
-        if((ch==0xFE89)||(ch==0xFE8A)){
-            return true;
-        }else{
-            return false;
-        }
-    }
-
-    /*
-     *Name     : isTashkeelCharFE
-     *Function : Returns true for Tashkeel characters in FE range else return false
-     */
-
-    private static boolean isTashkeelCharFE(char ch) {
-        return ( ch!=0xFE75 &&(ch>=0xFE70 && ch<= 0xFE7F) );
-    }
-
-    /*
-     * Name: isTashkeelOnTatweelChar
-     * Function: Checks if the Tashkeel Character is on Tatweel or not,if the
-     *           Tashkeel on tatweel (FE range), it returns 1 else if the
-     *           Tashkeel with shadda on tatweel (FC range)return 2 otherwise
-     *           returns 0
-     */
-    private static int isTashkeelOnTatweelChar(char ch){
-        if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75 && ch != SHADDA_TATWEEL_CHAR)
-        {
-            return tashkeelMedial [ch - 0xFE70];
-        } else if( (ch >= 0xfcf2 && ch <= 0xfcf4) || (ch == SHADDA_TATWEEL_CHAR)) {
-            return 2;
-        } else {
-            return 0;
-        }
-    }
-
-    /*
-     * Name: isIsolatedTashkeelChar
-     * Function: Checks if the Tashkeel Character is in the isolated form
-     *           (i.e. Unicode FE range) returns 1 else if the Tashkeel
-     *           with shadda is in the isolated form (i.e. Unicode FC range)
-     *           returns 1 otherwise returns 0
-     */
-    private static int isIsolatedTashkeelChar(char ch){
-        if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75){
-            return (1 - tashkeelMedial [ch - 0xFE70]);
-        } else if(ch >= 0xfc5e && ch <= 0xfc63){
-            return 1;
-        } else{
-            return 0;
-        }
-    }
-
-    /*
-     * Name    : isAlefChar
-     * Function: Returns 1 for Alef characters else return 0
-     */
-    private static boolean isAlefChar(char ch) {
-        return ch == '\u0622' || ch == '\u0623' || ch == '\u0625' || ch == '\u0627';
-    }
-
-    /*
-     * Name    : isLamAlefChar
-     * Function: Returns true for LamAlef characters else return false
-     */
-    private static boolean isLamAlefChar(char ch) {
-        return ch >= '\uFEF5' && ch <= '\uFEFC';
-    }
-
-    private static boolean isNormalizedLamAlefChar(char ch) {
-        return ch >= '\u065C' && ch <= '\u065F';
-    }
-
-    /*
-     * Name    : calculateSize
-     * Function: This function calculates the destSize to be used in preflighting
-     *           when the destSize is equal to 0
-     */
-    private int calculateSize(char[] source,
-                              int sourceStart,
-                              int sourceLength) {
-
-        int destSize = sourceLength;
-
-        switch (options & LETTERS_MASK) {
-        case LETTERS_SHAPE:
-        case LETTERS_SHAPE_TASHKEEL_ISOLATED:
-            if (isLogical) {
-                for (int i = sourceStart, e = sourceStart + sourceLength - 1; i < e; ++i) {
-                    if ((source[i] == LAM_CHAR && isAlefChar(source[i+1])) || isTashkeelCharFE(source[i])){
-                        --destSize;
-                    }
-                }
-            } else { // visual
-                for(int i = sourceStart + 1, e = sourceStart + sourceLength; i < e; ++i) {
-                    if ((source[i] == LAM_CHAR && isAlefChar(source[i-1])) || isTashkeelCharFE(source[i])) {
-                        --destSize;
-                    }
-                }
-            }
-            break;
-
-        case LETTERS_UNSHAPE:
-            for(int i = sourceStart, e = sourceStart + sourceLength; i < e; ++i) {
-                if (isLamAlefChar(source[i])) {
-                    destSize++;
-                }
-            }
-            break;
-
-        default:
-            break;
-        }
-
-        return destSize;
-    }
-
-
-    /*
-     * Name    : countSpaceSub
-     * Function: Counts number of times the subChar appears in the array
-     */
-    public static int countSpaceSub(char [] dest,int length, char subChar){
-        int i = 0;
-        int count = 0;
-        while (i < length) {
-          if (dest[i] == subChar) {
-              count++;
-              }
-          i++;
-        }
-        return count;
-    }
-
-    /*
-     * Name    : shiftArray
-     * Function: Shifts characters to replace space sub characters
-     */
-    public static void shiftArray(char [] dest,int start, int e, char subChar){
-        int w = e;
-        int r = e;
-        while (--r >= start) {
-          char ch = dest[r];
-          if (ch != subChar) {
-            --w;
-            if (w != r) {
-              dest[w] = ch;
-            }
-          }
-        }
-   }
-
-    /*
-     * Name    : flipArray
-     * Function: inverts array, so that start becomes end and vice versa
-     */
-      public static int flipArray(char [] dest, int start, int e, int w){
-        int r;
-        if (w > start) {
-        // shift, assume small buffer size so don't use arraycopy
-          r = w;
-          w = start;
-          while (r < e) {
-            dest[w++] = dest[r++];
-           }
-         } else {
-             w = e;
-         }
-        return w;
-      }
-
-    /*
-     * Name     : handleTashkeelWithTatweel
-     * Function : Replaces Tashkeel as following:
-     *            Case 1 :if the Tashkeel on tatweel, replace it with Tatweel.
-     *            Case 2 :if the Tashkeel aggregated with Shadda on Tatweel, replace
-     *                   it with Shadda on Tatweel.
-     *            Case 3: if the Tashkeel is isolated replace it with Space.
-     *
-     */
-    private static int handleTashkeelWithTatweel(char[] dest, int sourceLength) {
-                     int i;
-                     for(i = 0; i < sourceLength; i++){
-                         if((isTashkeelOnTatweelChar(dest[i]) == 1)){
-                             dest[i] = TATWEEL_CHAR;
-                        }else if((isTashkeelOnTatweelChar(dest[i]) == 2)){
-                             dest[i] = SHADDA_TATWEEL_CHAR;
-                        }else if((isIsolatedTashkeelChar(dest[i])==1) && dest[i] != SHADDA_CHAR){
-                             dest[i] = SPACE_CHAR;
-                        }
-                     }
-                     return sourceLength;
-    }
-
-    /*
-     *Name     : handleGeneratedSpaces
-     *Function : The shapeUnicode function converts Lam + Alef into LamAlef + space,
-     *           and Tashkeel to space.
-     *           handleGeneratedSpaces function puts these generated spaces
-     *           according to the options the user specifies. LamAlef and Tashkeel
-     *           spaces can be replaced at begin, at end, at near or decrease the
-     *           buffer size.
-     *
-     *           There is also Auto option for LamAlef and tashkeel, which will put
-     *           the spaces at end of the buffer (or end of text if the user used
-     *           the option SPACES_RELATIVE_TO_TEXT_BEGIN_END).
-     *
-     *           If the text type was visual_LTR and the option
-     *           SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected the END
-     *           option will place the space at the beginning of the buffer and
-     *           BEGIN will place the space at the end of the buffer.
-     */
-  private int handleGeneratedSpaces(char[] dest,
-            int start,
-            int length) {
-
-      int lenOptionsLamAlef = options & LAMALEF_MASK;
-      int lenOptionsTashkeel = options & TASHKEEL_MASK;
-      boolean lamAlefOn = false;
-      boolean tashkeelOn = false;
-
-      if (!isLogical & !spacesRelativeToTextBeginEnd) {
-          switch (lenOptionsLamAlef) {
-          case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
-          case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
-          default: break;
-         }
-          switch (lenOptionsTashkeel){
-          case TASHKEEL_BEGIN: lenOptionsTashkeel = TASHKEEL_END; break;
-          case TASHKEEL_END: lenOptionsTashkeel = TASHKEEL_BEGIN; break;
-          default: break;
-          }
-        }
-
-
-      if (lenOptionsLamAlef == LAMALEF_NEAR) {
-          for (int i = start, e = i + length; i < e; ++i) {
-              if (dest[i] == LAMALEF_SPACE_SUB) {
-                  dest[i] = SPACE_CHAR_FOR_LAMALEF;
-              }
-          }
-
-      } else {
-
-          final int e = start + length;
-          int wL = countSpaceSub(dest, length, LAMALEF_SPACE_SUB);
-          int wT = countSpaceSub(dest, length, TASHKEEL_SPACE_SUB);
-
-          if (lenOptionsLamAlef == LAMALEF_END){
-            lamAlefOn = true;
-          }
-          if (lenOptionsTashkeel == TASHKEEL_END){
-            tashkeelOn = true;
-          }
-
-
-          if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_END)) {
-            shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
-            while (wL > start) {
-                dest[--wL] = SPACE_CHAR;
-            }
-          }
-
-          if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_END)){
-            shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
-            while (wT > start) {
-                 dest[--wT] = SPACE_CHAR;
-            }
-          }
-
-          lamAlefOn = false;
-          tashkeelOn = false;
-
-          if (lenOptionsLamAlef == LAMALEF_RESIZE){
-            lamAlefOn = true;
-          }
-          if (lenOptionsTashkeel == TASHKEEL_RESIZE){
-            tashkeelOn = true;
-          }
-
-          if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_RESIZE)){
-              shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
-              wL = flipArray(dest,start,e, wL);
-              length = wL - start;
-          }
-          if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_RESIZE)) {
-              shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
-              wT = flipArray(dest,start,e, wT);
-              length = wT - start;
-          }
-
-          lamAlefOn = false;
-          tashkeelOn = false;
-
-          if ((lenOptionsLamAlef == LAMALEF_BEGIN) ||
-              (lenOptionsLamAlef == LAMALEF_AUTO)){
-                lamAlefOn = true;
-          }
-          if (lenOptionsTashkeel == TASHKEEL_BEGIN){
-                tashkeelOn = true;
-          }
-
-          if (lamAlefOn && ((lenOptionsLamAlef == LAMALEF_BEGIN)||
-                            (lenOptionsLamAlef == LAMALEF_AUTO))) { // spaces at beginning
-              shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
-               wL = flipArray(dest,start,e, wL);
-                  while (wL < e) {
-                      dest[wL++] = SPACE_CHAR;
-                  }
-              }
-              if(tashkeelOn && (lenOptionsTashkeel == TASHKEEL_BEGIN)){
-               shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
-               wT = flipArray(dest,start,e, wT);
-                  while (wT < e) {
-                      dest[wT++] = SPACE_CHAR;
-                  }
-              }
-           }
-
-      return length;
-  }
-
-
-  /*
-   *Name     :expandCompositCharAtBegin
-   *Function :Expands the LamAlef character to Lam and Alef consuming the required
-   *         space from beginning of the buffer. If the text type was visual_LTR
-   *         and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected
-   *         the spaces will be located at end of buffer.
-   *         If there are no spaces to expand the LamAlef, an exception is thrown.
-*/
- private boolean expandCompositCharAtBegin(char[] dest,int start, int length,
-                            int lacount) {
-     boolean spaceNotFound = false;
-
-     if (lacount > countSpacesRight(dest, start, length)) {
-         spaceNotFound = true;
-         return spaceNotFound;
-     }
-     for (int r = start + length - lacount, w = start + length; --r >= start;) {
-         char ch = dest[r];
-         if (isNormalizedLamAlefChar(ch)) {
-             dest[--w] = LAM_CHAR;
-             dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
-         } else {
-             dest[--w] = ch;
-         }
-     }
-     return spaceNotFound;
-
-  }
-
-  /*
-   *Name     : expandCompositCharAtEnd
-   *Function : Expands the LamAlef character to Lam and Alef consuming the
-   *           required space from end of the buffer. If the text type was
-   *           Visual LTR and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END
-   *           was used, the spaces will be consumed from begin of buffer. If
-   *           there are no spaces to expand the LamAlef, an exception is thrown.
-   */
-
-  private boolean  expandCompositCharAtEnd(char[] dest,int start, int length,
-                          int lacount){
-      boolean spaceNotFound = false;
-
-      if (lacount > countSpacesLeft(dest, start, length)) {
-          spaceNotFound = true;
-          return spaceNotFound;
-      }
-      for (int r = start + lacount, w = start, e = start + length; r < e; ++r) {
-          char ch = dest[r];
-          if (isNormalizedLamAlefChar(ch)) {
-              dest[w++] = convertNormalizedLamAlef[ch - '\u065C'];
-              dest[w++] = LAM_CHAR;
-          } else {
-              dest[w++] = ch;
-          }
-      }
-      return spaceNotFound;
-  }
-
-  /*
-   *Name     : expandCompositCharAtNear
-   *Function : Expands the LamAlef character into Lam + Alef, YehHamza character
-   *           into Yeh + Hamza, SeenFamily character into SeenFamily character
-   *           + Tail, while consuming the space next to the character.
-   */
-
-  private boolean expandCompositCharAtNear(char[] dest,int start, int length,
-                                       int yehHamzaOption, int seenTailOption, int lamAlefOption){
-
-      boolean spaceNotFound = false;
-
-
-
-      if (isNormalizedLamAlefChar(dest[start])) {
-          spaceNotFound = true;
-          return spaceNotFound;
-      }
-      for (int i = start + length; --i >=start;) {
-          char ch = dest[i];
-          if (lamAlefOption == 1 && isNormalizedLamAlefChar(ch)) {
-              if (i>start &&dest[i-1] == SPACE_CHAR) {
-                  dest[i] = LAM_CHAR;
-                  dest[--i] = convertNormalizedLamAlef[ch - '\u065C'];
-              } else {
-                  spaceNotFound = true;
-                  return spaceNotFound;
-              }
-          }else if(seenTailOption == 1 && isSeenTailFamilyChar(ch) == 1){
-              if(i>start &&dest[i-1] == SPACE_CHAR){
-                  dest[i-1] = tailChar;
-              } else{
-                  spaceNotFound = true;
-                  return spaceNotFound;
-              }
-          }else if(yehHamzaOption == 1 && isYehHamzaChar(ch)){
-
-               if(i>start &&dest[i-1] == SPACE_CHAR){
-                  dest[i] = yehHamzaToYeh[ch - YEH_HAMZAFE_CHAR];
-                  dest[i-1] = HAMZAFE_CHAR;
-              }else{
-                  spaceNotFound = true;
-                  return spaceNotFound;
-                }
-
-
-          }
-      }
-      return false;
-
-  }
-
-    /*
-     * Name    : expandCompositChar
-     * Function: LamAlef needs special handling as the LamAlef is
-     *           one character while expanding it will give two
-     *           characters Lam + Alef, so we need to expand the LamAlef
-     *           in near or far spaces according to the options the user
-     *           specifies or increase the buffer size.
-     *           Dest has enough room for the expansion if we are growing.
-     *           lamalef are normalized to the 'special characters'
-     */
-    private int expandCompositChar(char[] dest,
-                              int start,
-                              int length,
-                              int lacount,
-                              int shapingMode) throws ArabicShapingException {
-
-        int lenOptionsLamAlef = options & LAMALEF_MASK;
-        int lenOptionsSeen = options & SEEN_MASK;
-        int lenOptionsYehHamza = options & YEHHAMZA_MASK;
-        boolean spaceNotFound = false;
-
-        if (!isLogical && !spacesRelativeToTextBeginEnd) {
-            switch (lenOptionsLamAlef) {
-            case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
-            case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
-            default: break;
-            }
-        }
-
-        if(shapingMode == 1){
-            if(lenOptionsLamAlef == LAMALEF_AUTO){
-                if(isLogical){
-                    spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
-                    if(spaceNotFound){
-                        spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
-                    }
-                    if(spaceNotFound){
-                        spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
-                    }
-                    if(spaceNotFound){
-                        throw new ArabicShapingException("No spacefor lamalef");
-                    }
-                }else{
-                    spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
-                    if(spaceNotFound){
-                        spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
-                    }
-                    if(spaceNotFound){
-                        spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
-                    }
-                    if(spaceNotFound){
-                        throw new ArabicShapingException("No spacefor lamalef");
-                    }
-                }
-            }else if(lenOptionsLamAlef == LAMALEF_END){
-                spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
-                if(spaceNotFound){
-                    throw new ArabicShapingException("No spacefor lamalef");
-                }
-            }else if(lenOptionsLamAlef == LAMALEF_BEGIN){
-                spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
-                if(spaceNotFound){
-                    throw new ArabicShapingException("No spacefor lamalef");
-                }
-            }else if(lenOptionsLamAlef == LAMALEF_NEAR){
-                spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
-                if(spaceNotFound){
-                    throw new ArabicShapingException("No spacefor lamalef");
-            }
-            }else if(lenOptionsLamAlef == LAMALEF_RESIZE){
-                for (int r = start + length, w = r + lacount; --r >= start;) {
-                    char ch = dest[r];
-                    if (isNormalizedLamAlefChar(ch)) {
-                        dest[--w] = '\u0644';
-                        dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
-                    } else {
-                        dest[--w] = ch;
-                    }
-                }
-                length += lacount;
-            }
-            }else{
-                if(lenOptionsSeen == SEEN_TWOCELL_NEAR){
-                spaceNotFound = expandCompositCharAtNear(dest, start, length,0,1,0);
-                if(spaceNotFound){
-                    throw new ArabicShapingException("No space for Seen tail expansion");
-                }
-            }
-            if(lenOptionsYehHamza == YEHHAMZA_TWOCELL_NEAR){
-                spaceNotFound = expandCompositCharAtNear(dest, start, length,1,0,0);
-                if(spaceNotFound){
-                    throw new ArabicShapingException("No space for YehHamza expansion");
-                }
-            }
-            }
-        return length;
-    }
-
-
-    /* Convert the input buffer from FExx Range into 06xx Range
-     * to put all characters into the 06xx range
-     * even the lamalef is converted to the special region in
-     * the 06xx range.  Return the number of lamalef chars found.
-     */
-    private int normalize(char[] dest, int start, int length) {
-        int lacount = 0;
-        for (int i = start, e = i + length; i < e; ++i) {
-            char ch = dest[i];
-            if (ch >= '\uFE70' && ch <= '\uFEFC') {
-                if (isLamAlefChar(ch)) {
-                    ++lacount;
-                }
-                dest[i] = (char)convertFEto06[ch - '\uFE70'];
-            }
-        }
-        return lacount;
-    }
-
-    /*
-     * Name    : deshapeNormalize
-     * Function: Convert the input buffer from FExx Range into 06xx Range
-     *           even the lamalef is converted to the special region in the 06xx range.
-     *           According to the options the user enters, all seen family characters
-     *           followed by a tail character are merged to seen tail family character and
-     *           any yeh followed by a hamza character are merged to yehhamza character.
-     *           Method returns the number of lamalef chars found.
-     */
-    private int deshapeNormalize(char[] dest, int start, int length) {
-        int lacount = 0;
-        int yehHamzaComposeEnabled = 0;
-        int seenComposeEnabled = 0;
-
-        yehHamzaComposeEnabled = ((options&YEHHAMZA_MASK) == YEHHAMZA_TWOCELL_NEAR) ? 1 : 0;
-        seenComposeEnabled = ((options&SEEN_MASK) == SEEN_TWOCELL_NEAR)? 1 : 0;
-
-        for (int i = start, e = i + length; i < e; ++i) {
-            char ch = dest[i];
-
-        if( (yehHamzaComposeEnabled == 1) && ((ch == HAMZA06_CHAR) || (ch == HAMZAFE_CHAR))
-               && (i < (length - 1)) && isAlefMaksouraChar(dest[i+1] )) {
-                dest[i] = SPACE_CHAR;
-                dest[i+1] = YEH_HAMZA_CHAR;
-       } else if ( (seenComposeEnabled == 1) && (isTailChar(ch)) && (i< (length - 1))
-                       && (isSeenTailFamilyChar(dest[i+1])==1) ) {
-               dest[i] = SPACE_CHAR;
-       }
-       else if (ch >= '\uFE70' && ch <= '\uFEFC') {
-                if (isLamAlefChar(ch)) {
-                    ++lacount;
-                }
-                dest[i] = (char)convertFEto06[ch - '\uFE70'];
-            }
-        }
-        return lacount;
-    }
-
-    /*
-     * Name    : shapeUnicode
-     * Function: Converts an Arabic Unicode buffer in 06xx Range into a shaped
-     *           arabic Unicode buffer in FExx Range
-     */
-    private int shapeUnicode(char[] dest,
-                             int start,
-                             int length,
-                             int destSize,
-                             int tashkeelFlag)throws ArabicShapingException {
-
-        int lamalef_count = normalize(dest, start, length);
-
-        // resolve the link between the characters.
-        // Arabic characters have four forms: Isolated, Initial, Medial and Final.
-        // Tashkeel characters have two, isolated or medial, and sometimes only isolated.
-        // tashkeelFlag == 0: shape normally, 1: shape isolated, 2: don't shape
-
-        boolean lamalef_found = false, seenfam_found = false;
-        boolean yehhamza_found = false, tashkeel_found = false;
-        int i = start + length - 1;
-        int currLink = getLink(dest[i]);
-        int nextLink = 0;
-        int prevLink = 0;
-        int lastLink = 0;
-        //int prevPos = i;
-        int lastPos = i;
-        int nx = -2;
-        int nw = 0;
-
-        while (i >= 0) {
-            // If high byte of currLink > 0 then there might be more than one shape
-            if ((currLink & '\uFF00') > 0 || isTashkeelChar(dest[i])) {
-                nw = i - 1;
-                nx = -2;
-                while (nx < 0) { // we need to know about next char
-                    if (nw == -1) {
-                        nextLink = 0;
-                        nx = Integer.MAX_VALUE;
-                    } else {
-                        nextLink = getLink(dest[nw]);
-                        if ((nextLink & IRRELEVANT) == 0) {
-                            nx = nw;
-                        } else {
-                            --nw;
-                        }
-                    }
-                }
-
-                if (((currLink & ALEFTYPE) > 0) && ((lastLink & LAMTYPE) > 0)) {
-                    lamalef_found = true;
-                    char wLamalef = changeLamAlef(dest[i]); // get from 0x065C-0x065f
-                    if (wLamalef != '\u0000') {
-                        // replace alef by marker, it will be removed later
-                        dest[i] = '\uffff';
-                        dest[lastPos] = wLamalef;
-                        i = lastPos;
-                    }
-
-                    lastLink = prevLink;
-                    currLink = getLink(wLamalef); // requires '\u0000', unfortunately
-                }
-                if ((i > 0) && (dest[i-1] == SPACE_CHAR))
-                {
-                    if ( isSeenFamilyChar(dest[i]) == 1){
-                        seenfam_found = true;
-                    } else if (dest[i] == YEH_HAMZA_CHAR) {
-                        yehhamza_found = true;
-                    }
-                }
-                else if(i==0){
-                    if ( isSeenFamilyChar(dest[i]) == 1){
-                        seenfam_found = true;
-                    } else if (dest[i] == YEH_HAMZA_CHAR) {
-                        yehhamza_found = true;
-                    }
-                }
-
-
-                // get the proper shape according to link ability of neighbors
-                // and of character; depends on the order of the shapes
-                // (isolated, initial, middle, final) in the compatibility area
-
-                int flag = specialChar(dest[i]);
-
-                int shape = shapeTable[nextLink & LINK_MASK]
-                    [lastLink & LINK_MASK]
-                    [currLink & LINK_MASK];
-
-                if (flag == 1) {
-                    shape &= 0x1;
-                } else if (flag == 2) {
-                    if (tashkeelFlag == 0 &&
-                        ((lastLink & LINKL) != 0) &&
-                        ((nextLink & LINKR) != 0) &&
-                        dest[i] != '\u064C' &&
-                        dest[i] != '\u064D' &&
-                        !((nextLink & ALEFTYPE) == ALEFTYPE &&
-                          (lastLink & LAMTYPE) == LAMTYPE)) {
-
-                        shape = 1;
-                    } else {
-                        shape = 0;
-                    }
-                }
-                if (flag == 2) {
-                    if (tashkeelFlag == 2) {
-                        dest[i] = TASHKEEL_SPACE_SUB;
-                        tashkeel_found = true;
-                    }
-                    else{
-                        dest[i] = (char)('\uFE70' + irrelevantPos[dest[i] - '\u064B'] + shape);
-                    }
-                    // else leave tashkeel alone
-                } else {
-                    dest[i] = (char)('\uFE70' + (currLink >> 8) + shape);
-                }
-            }
-
-            // move one notch forward
-            if ((currLink & IRRELEVANT) == 0) {
-                prevLink = lastLink;
-                lastLink = currLink;
-                //prevPos = lastPos;
-                lastPos = i;
-            }
-
-            --i;
-            if (i == nx) {
-                currLink = nextLink;
-                nx = -2;
-            } else if (i != -1) {
-                currLink = getLink(dest[i]);
-            }
-        }
-
-        // If we found a lam/alef pair in the buffer
-        // call handleGeneratedSpaces to remove the spaces that were added
-
-        destSize = length;
-        if (lamalef_found || tashkeel_found) {
-            destSize = handleGeneratedSpaces(dest, start, length);
-        }
-        if (seenfam_found || yehhamza_found){
-            destSize = expandCompositChar(dest, start, destSize, lamalef_count, SHAPE_MODE);
-        }
-        return destSize;
-    }
-
-    /*
-     * Name    : deShapeUnicode
-     * Function: Converts an Arabic Unicode buffer in FExx Range into unshaped
-     *           arabic Unicode buffer in 06xx Range
-     */
-    private int deShapeUnicode(char[] dest,
-                               int start,
-                               int length,
-                               int destSize) throws ArabicShapingException {
-
-        int lamalef_count = deshapeNormalize(dest, start, length);
-
-        // If there was a lamalef in the buffer call expandLamAlef
-        if (lamalef_count != 0) {
-            // need to adjust dest to fit expanded buffer... !!!
-            destSize = expandCompositChar(dest, start, length, lamalef_count,DESHAPE_MODE);
-        } else {
-            destSize = length;
-        }
-
-        return destSize;
-    }
-
-    private int internalShape(char[] source,
-                              int sourceStart,
-                              int sourceLength,
-                              char[] dest,
-                              int destStart,
-                              int destSize) throws ArabicShapingException {
-
-        if (sourceLength == 0) {
-            return 0;
-        }
-
-        if (destSize == 0) {
-            if (((options & LETTERS_MASK) != LETTERS_NOOP) &&
-                ((options & LAMALEF_MASK) == LAMALEF_RESIZE)) {
-
-                return calculateSize(source, sourceStart, sourceLength);
-            } else {
-                return sourceLength; // by definition
-            }
-        }
-
-        // always use temp buffer
-        char[] temp = new char[sourceLength * 2]; // all lamalefs requiring expansion
-        System.arraycopy(source, sourceStart, temp, 0, sourceLength);
-
-        if (isLogical) {
-            invertBuffer(temp, 0, sourceLength);
-        }
-
-        int outputSize = sourceLength;
-
-        switch (options & LETTERS_MASK) {
-        case LETTERS_SHAPE_TASHKEEL_ISOLATED:
-            outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 1);
-            break;
-
-        case LETTERS_SHAPE:
-            if( ((options&TASHKEEL_MASK)> 0) &&
-                ((options&TASHKEEL_MASK) !=TASHKEEL_REPLACE_BY_TATWEEL)) {
-                   /* Call the shaping function with tashkeel flag == 2 for removal of tashkeel */
-                outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 2);
-                }else {
-                   //default Call the shaping function with tashkeel flag == 1 */
-                    outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 0);
-
-                   /*After shaping text check if user wants to remove tashkeel and replace it with tatweel*/
-                   if( (options&TASHKEEL_MASK) == TASHKEEL_REPLACE_BY_TATWEEL){
-                       outputSize = handleTashkeelWithTatweel(temp,sourceLength);
-                   }
-               }
-            break;
-
-        case LETTERS_UNSHAPE:
-            outputSize = deShapeUnicode(temp, 0, sourceLength, destSize);
-            break;
-
-        default:
-            break;
-        }
-
-        if (outputSize > destSize) {
-            throw new ArabicShapingException("not enough room for result data");
-        }
-
-        if ((options & DIGITS_MASK) != DIGITS_NOOP) {
-            char digitBase = '\u0030'; // European digits
-            switch (options & DIGIT_TYPE_MASK) {
-            case DIGIT_TYPE_AN:
-                digitBase = '\u0660';  // Arabic-Indic digits
-                break;
-
-            case DIGIT_TYPE_AN_EXTENDED:
-                digitBase = '\u06f0';  // Eastern Arabic-Indic digits (Persian and Urdu)
-                break;
-
-            default:
-                break;
-            }
-
-            switch (options & DIGITS_MASK) {
-            case DIGITS_EN2AN:
-                {
-                    int digitDelta = digitBase - '\u0030';
-                    for (int i = 0; i < outputSize; ++i) {
-                        char ch = temp[i];
-                        if (ch <= '\u0039' && ch >= '\u0030') {
-                            temp[i] += digitDelta;
-                        }
-                    }
-                }
-                break;
-
-            case DIGITS_AN2EN:
-                {
-                    char digitTop = (char)(digitBase + 9);
-                    int digitDelta = '\u0030' - digitBase;
-                    for (int i = 0; i < outputSize; ++i) {
-                        char ch = temp[i];
-                        if (ch <= digitTop && ch >= digitBase) {
-                            temp[i] += digitDelta;
-                        }
-                    }
-                }
-                break;
-
-            case DIGITS_EN2AN_INIT_LR:
-                shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, false);
-                break;
-
-            case DIGITS_EN2AN_INIT_AL:
-                shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, true);
-                break;
-
-            default:
-                break;
-            }
-        }
-
-        if (isLogical) {
-            invertBuffer(temp, 0, outputSize);
-        }
-
-        System.arraycopy(temp, 0, dest, destStart, outputSize);
-
-        return outputSize;
-    }
-
-    private static class ArabicShapingException extends RuntimeException {
-        ArabicShapingException(String msg) {
-            super(msg);
-        }
-    }
-}
diff --git a/icu4j/license.html b/icu4j/license.html
deleted file mode 100644
index b905ddf..0000000
--- a/icu4j/license.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
-
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></meta>
-<title>ICU License - ICU 1.8.1 and later</title>
-</head>
-
-<body BGCOLOR="#ffffff">
-<h2>ICU License - ICU 1.8.1 and later</h2>
-
-<p>COPYRIGHT AND PERMISSION NOTICE</p>
-
-<p>
-Copyright (c) 1995-2006 International Business Machines Corporation and others
-</p>
-<p>
-All rights reserved.
-</p>
-<p>
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, and/or sell
-copies of the Software, and to permit persons
-to whom the Software is furnished to do so, provided that the above
-copyright notice(s) and this permission notice appear in all copies
-of the Software and that both the above copyright notice(s) and this
-permission notice appear in supporting documentation.
-</p>
-<p>
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL
-THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM,
-OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
-RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
-USE OR PERFORMANCE OF THIS SOFTWARE.
-</p>
-<p>
-Except as contained in this notice, the name of a copyright holder shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization of the copyright holder.
-</p>
-
-<hr>
-<p><small>
-All trademarks and registered trademarks mentioned herein are the property of their respective owners.
-</small></p>
-</body>
-</html>
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 48f5bf3..5b45d70 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -855,6 +855,7 @@
         DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
         DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH,
         DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH,
+        DENSITY_XXXHIGH = ACONFIGURATION_DENSITY_XXXHIGH,
         DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
     };
     
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 2111a56..d533fa0 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -28,6 +28,7 @@
 		PathTessellator.cpp \
 		Program.cpp \
 		ProgramCache.cpp \
+		RenderBufferCache.cpp \
 		ResourceCache.cpp \
 		ShapeCache.cpp \
 		SkiaColorFilter.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 492bb7d..74201d1 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -186,6 +186,8 @@
             textureCache.getSize(), textureCache.getMaxSize());
     log.appendFormat("  LayerCache           %8d / %8d\n",
             layerCache.getSize(), layerCache.getMaxSize());
+    log.appendFormat("  RenderBufferCache    %8d / %8d\n",
+            renderBufferCache.getSize(), renderBufferCache.getMaxSize());
     log.appendFormat("  GradientCache        %8d / %8d\n",
             gradientCache.getSize(), gradientCache.getMaxSize());
     log.appendFormat("  PathCache            %8d / %8d\n",
@@ -215,6 +217,7 @@
     uint32_t total = 0;
     total += textureCache.getSize();
     total += layerCache.getSize();
+    total += renderBufferCache.getSize();
     total += gradientCache.getSize();
     total += pathCache.getSize();
     total += dropShadowCache.getSize();
@@ -298,6 +301,7 @@
             // fall through
         case kFlushMode_Layers:
             layerCache.clear();
+            renderBufferCache.clear();
             break;
     }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 0fa54fb..d70c0e3 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -29,6 +29,7 @@
 #include "GammaFontRenderer.h"
 #include "TextureCache.h"
 #include "LayerCache.h"
+#include "RenderBufferCache.h"
 #include "GradientCache.h"
 #include "PatchCache.h"
 #include "ProgramCache.h"
@@ -249,6 +250,7 @@
 
     TextureCache textureCache;
     LayerCache layerCache;
+    RenderBufferCache renderBufferCache;
     GradientCache gradientCache;
     ProgramCache programCache;
     PathCache pathCache;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 5f8baac..20eb5e1 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -44,6 +44,9 @@
 // Turn on to display info about layers
 #define DEBUG_LAYERS 0
 
+// Turn on to display info about render buffers
+#define DEBUG_RENDER_BUFFERS 0
+
 // Turn on to make stencil operations easier to debug
 #define DEBUG_STENCIL 0
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 9247b1d..1899002 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -101,14 +101,13 @@
 
 void Layer::removeFbo(bool flush) {
     if (stencil) {
-        // TODO: recycle & cache instead of simply deleting
         GLuint previousFbo;
         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
 
-        delete stencil;
+        Caches::getInstance().renderBufferCache.put(stencil);
         stencil = NULL;
     }
 
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 4278464..a0709af 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 
 #include "Caches.h"
-#include "Debug.h"
 #include "LayerCache.h"
 #include "Properties.h"
 
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 7720b42..221bfe0 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -19,7 +19,6 @@
 
 #include "Debug.h"
 #include "Layer.h"
-#include "Properties.h"
 #include "utils/SortedList.h"
 
 namespace android {
@@ -54,7 +53,7 @@
      * size of the cache goes down.
      *
      * @param width The desired width of the layer
-     * @param width The desired height of the layer
+     * @param height The desired height of the layer
      */
     Layer* get(const uint32_t width, const uint32_t height);
 
@@ -91,6 +90,7 @@
      */
     void dump();
 
+private:
     struct LayerEntry {
         LayerEntry():
             mLayer(NULL), mWidth(0), mHeight(0) {
@@ -115,12 +115,19 @@
             return compare(*this, other) != 0;
         }
 
+        friend inline int strictly_order_type(const LayerEntry& lhs, const LayerEntry& rhs) {
+            return LayerEntry::compare(lhs, rhs) < 0;
+        }
+
+        friend inline int compare_type(const LayerEntry& lhs, const LayerEntry& rhs) {
+            return LayerEntry::compare(lhs, rhs);
+        }
+
         Layer* mLayer;
         uint32_t mWidth;
         uint32_t mHeight;
     }; // struct LayerEntry
 
-private:
     void deleteLayer(Layer* layer);
 
     SortedList<LayerEntry> mCache;
@@ -129,15 +136,6 @@
     uint32_t mMaxSize;
 }; // class LayerCache
 
-inline int strictly_order_type(const LayerCache::LayerEntry& lhs,
-        const LayerCache::LayerEntry& rhs) {
-    return LayerCache::LayerEntry::compare(lhs, rhs) < 0;
-}
-
-inline int compare_type(const LayerCache::LayerEntry& lhs, const LayerCache::LayerEntry& rhs) {
-    return LayerCache::LayerEntry::compare(lhs, rhs);
-}
-
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 08e2332..2431e54 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1179,6 +1179,10 @@
 
             delete bounds;
         }
+        // We must clear the list of dirty rects before we
+        // call setupDraw() to prevent stencil setup to do
+        // the same thing again
+        mLayers.clear();
 
         setupDraw(false);
         setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -1195,9 +1199,8 @@
         for (uint32_t i = 0; i < count; i++) {
             delete mLayers.itemAt(i);
         }
+        mLayers.clear();
     }
-
-    mLayers.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1270,11 +1273,8 @@
         // attach the new render buffer then turn tiling back on
         endTiling();
 
-        RenderBuffer* buffer = new RenderBuffer(
+        RenderBuffer* buffer = mCaches.renderBufferCache.get(
                 Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
-        buffer->bind();
-        buffer->allocate();
-
         layer->setStencilRenderBuffer(buffer);
 
         startTiling(layer->clipRect, layer->layer.getHeight());
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1e8765b..0c75242 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -34,9 +34,9 @@
 // Textures used by layers must have dimensions multiples of this number
 #define LAYER_SIZE 64
 
-// Defines the size in bits of the stencil buffer
+// Defines the size in bits of the stencil buffer for the framebuffer
 // Note: Only 1 bit is required for clipping but more bits are required
-// to properly implement the winding fill rule when rasterizing paths
+// to properly implement overdraw debugging
 #define STENCIL_BUFFER_SIZE 8
 
 /**
@@ -85,6 +85,7 @@
 // These properties are defined in mega-bytes
 #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
 #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
+#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
 #define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
 #define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
 #define PROPERTY_SHAPE_CACHE_SIZE "ro.hwui.shape_cache_size"
@@ -130,6 +131,7 @@
 
 #define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
 #define DEFAULT_LAYER_CACHE_SIZE 16.0f
+#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
 #define DEFAULT_PATH_CACHE_SIZE 4.0f
 #define DEFAULT_SHAPE_CACHE_SIZE 1.0f
 #define DEFAULT_PATCH_CACHE_SIZE 512
diff --git a/libs/hwui/RenderBuffer.h b/libs/hwui/RenderBuffer.h
index 927f265..a9ad3d7 100644
--- a/libs/hwui/RenderBuffer.h
+++ b/libs/hwui/RenderBuffer.h
@@ -39,7 +39,7 @@
     }
 
     ~RenderBuffer() {
-        if (mName && mAllocated) {
+        if (mName) {
             glDeleteRenderbuffers(1, &mName);
         }
     }
@@ -154,6 +154,29 @@
         return false;
     }
 
+    /**
+     * Returns the name of the specified render buffer format.
+     */
+    static const char* formatName(GLenum format) {
+        switch (format) {
+            case GL_STENCIL_INDEX8:
+                return "STENCIL_8";
+            case GL_STENCIL_INDEX1_OES:
+                return "STENCIL_1";
+            case GL_STENCIL_INDEX4_OES:
+                return "STENCIL_4";
+            case GL_DEPTH_COMPONENT16:
+                return "DEPTH_16";
+            case GL_RGBA4:
+                return "RGBA_444";
+            case GL_RGB565:
+                return "RGB_565";
+            case GL_RGB5_A1:
+                return "RGBA_5551";
+        }
+        return "Unknown";
+    }
+
 private:
     GLenum mFormat;
 
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
new file mode 100644
index 0000000..830a13a
--- /dev/null
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Debug.h"
+#include "Properties.h"
+#include "RenderBufferCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#if DEBUG_RENDER_BUFFERS
+    #define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+    #define RENDER_BUFFER_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) {
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, NULL) > 0) {
+        INIT_LOGD("  Setting render buffer cache size to %sMB", property);
+        setMaxSize(MB(atof(property)));
+    } else {
+        INIT_LOGD("  Using default render buffer cache size of %.2fMB",
+                DEFAULT_RENDER_BUFFER_CACHE_SIZE);
+    }
+}
+
+RenderBufferCache::~RenderBufferCache() {
+    clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t RenderBufferCache::getSize() {
+    return mSize;
+}
+
+uint32_t RenderBufferCache::getMaxSize() {
+    return mMaxSize;
+}
+
+void RenderBufferCache::setMaxSize(uint32_t maxSize) {
+    clear();
+    mMaxSize = maxSize;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+int RenderBufferCache::RenderBufferEntry::compare(
+        const RenderBufferCache::RenderBufferEntry& lhs,
+        const RenderBufferCache::RenderBufferEntry& rhs) {
+    int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
+    if (deltaInt != 0) return deltaInt;
+
+    deltaInt = int(lhs.mHeight) - int(rhs.mHeight);
+    if (deltaInt != 0) return deltaInt;
+
+    return int(lhs.mFormat) - int(rhs.mFormat);
+}
+
+void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
+    if (buffer) {
+        RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
+                RenderBuffer::formatName(buffer->getFormat()),
+                buffer->getWidth(), buffer->getHeight());
+
+        mSize -= buffer->getSize();
+        delete buffer;
+    }
+}
+
+void RenderBufferCache::clear() {
+    size_t count = mCache.size();
+    for (size_t i = 0; i < count; i++) {
+        deleteBuffer(mCache.itemAt(i).mBuffer);
+    }
+    mCache.clear();
+}
+
+RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
+    RenderBuffer* buffer = NULL;
+
+    RenderBufferEntry entry(format, width, height);
+    ssize_t index = mCache.indexOf(entry);
+
+    if (index >= 0) {
+        entry = mCache.itemAt(index);
+        mCache.removeAt(index);
+
+        buffer = entry.mBuffer;
+        mSize -= buffer->getSize();
+
+        RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
+                RenderBuffer::formatName(format), width, height);
+    } else {
+        buffer = new RenderBuffer(format, width, height);
+
+        RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
+                RenderBuffer::formatName(format), width, height);
+    }
+
+    buffer->bind();
+    buffer->allocate();
+
+    return buffer;
+}
+
+bool RenderBufferCache::put(RenderBuffer* buffer) {
+    if (!buffer) return false;
+
+    const uint32_t size = buffer->getSize();
+    if (size < mMaxSize) {
+        while (mSize + size > mMaxSize) {
+            size_t position = 0;
+
+            RenderBuffer* victim = mCache.itemAt(position).mBuffer;
+            deleteBuffer(victim);
+            mCache.removeAt(position);
+        }
+
+        RenderBufferEntry entry(buffer);
+
+        mCache.add(entry);
+        mSize += size;
+
+        RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
+                RenderBuffer::formatName(buffer->getFormat()),
+                buffer->getWidth(), buffer->getHeight());
+
+        return true;
+    }
+    return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h
new file mode 100644
index 0000000..af8060f
--- /dev/null
+++ b/libs/hwui/RenderBufferCache.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_RENDER_BUFFER_CACHE_H
+#define ANDROID_HWUI_RENDER_BUFFER_CACHE_H
+
+#include <GLES2/gl2.h>
+
+#include "RenderBuffer.h"
+#include "utils/SortedList.h"
+
+namespace android {
+namespace uirenderer {
+
+class RenderBufferCache {
+public:
+    RenderBufferCache();
+    ~RenderBufferCache();
+
+    /**
+     * Returns a buffer with the exact specified dimensions. If no suitable
+     * buffer can be found, a new one is created and returned. If creating a
+     * new buffer fails, NULL is returned.
+     *
+     * When a buffer is obtained from the cache, it is removed and the total
+     * size of the cache goes down.
+     *
+     * The returned buffer is always allocated and bound
+     * (see RenderBuffer::isAllocated()).
+     *
+     * @param format The desired render buffer format
+     * @param width The desired width of the buffer
+     * @param height The desired height of the buffer
+     */
+    RenderBuffer* get(GLenum format, const uint32_t width, const uint32_t height);
+
+    /**
+     * Adds the buffer to the cache. The buffer will not be added if there is
+     * not enough space available. Adding a buffer can cause other buffer to
+     * be removed from the cache.
+     *
+     * @param buffer The render buffer to add to the cache
+     *
+     * @return True if the buffer was added, false otherwise.
+     */
+    bool put(RenderBuffer* buffer);
+    /**
+     * Clears the cache. This causes all layers to be deleted.
+     */
+    void clear();
+
+    /**
+     * Sets the maximum size of the cache in bytes.
+     */
+    void setMaxSize(uint32_t maxSize);
+    /**
+     * Returns the maximum size of the cache in bytes.
+     */
+    uint32_t getMaxSize();
+    /**
+     * Returns the current size of the cache in bytes.
+     */
+    uint32_t getSize();
+
+private:
+    struct RenderBufferEntry {
+        RenderBufferEntry():
+            mBuffer(NULL), mWidth(0), mHeight(0) {
+        }
+
+        RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
+            mBuffer(NULL), mFormat(format), mWidth(width), mHeight(height) {
+        }
+
+        RenderBufferEntry(RenderBuffer* buffer):
+            mBuffer(buffer), mFormat(buffer->getFormat()),
+            mWidth(buffer->getWidth()), mHeight(buffer->getHeight()) {
+        }
+
+        static int compare(const RenderBufferEntry& lhs, const RenderBufferEntry& rhs);
+
+        bool operator==(const RenderBufferEntry& other) const {
+            return compare(*this, other) == 0;
+        }
+
+        bool operator!=(const RenderBufferEntry& other) const {
+            return compare(*this, other) != 0;
+        }
+
+        friend inline int strictly_order_type(const RenderBufferEntry& lhs,
+                const RenderBufferEntry& rhs) {
+            return RenderBufferEntry::compare(lhs, rhs) < 0;
+        }
+
+        friend inline int compare_type(const RenderBufferEntry& lhs,
+                const RenderBufferEntry& rhs) {
+            return RenderBufferEntry::compare(lhs, rhs);
+        }
+
+        RenderBuffer* mBuffer;
+        GLenum mFormat;
+        uint32_t mWidth;
+        uint32_t mHeight;
+    }; // struct RenderBufferEntry
+
+    void deleteBuffer(RenderBuffer* buffer);
+
+    SortedList<RenderBufferEntry> mCache;
+
+    uint32_t mSize;
+    uint32_t mMaxSize;
+}; // class RenderBufferCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 1afcb46..1a75ea8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -189,7 +189,10 @@
     vOffset += glyph->mBitmapTop + height;
 
     SkPoint destination[4];
-    measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+    bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+    if (!ok) {
+        ALOGW("The path for drawTextOnPath is empty or null");
+    }
 
     // Move along the tangent and offset by the normal
     destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 035b282..2e4fa4b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1526,6 +1526,16 @@
 
     /**
      * @hide
+     * Checks whether any music or media is actively playing on a remote device (e.g. wireless
+     *   display). Note that BT audio sinks are not considered remote devices.
+     * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
+     */
+    public boolean isMusicActiveRemotely() {
+        return AudioSystem.isStreamActiveRemotely(STREAM_MUSIC, 0);
+    }
+
+    /**
+     * @hide
      * Checks whether speech recognition is active
      * @return true if a recording with source {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}
      *    is underway.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index dde2979..4a33743 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -111,6 +111,14 @@
     public static native boolean isStreamActive(int stream, int inPastMs);
 
     /*
+     * Checks whether the specified stream type is active on a remotely connected device. The notion
+     * of what constitutes a remote device is enforced by the audio policy manager of the platform.
+     *
+     * return true if any track playing on this stream is active on a remote device.
+     */
+    public static native boolean isStreamActiveRemotely(int stream, int inPastMs);
+
+    /*
      * Checks whether the specified audio source is active.
      *
      * return true if any recorder using this source is currently recording
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index f930a03..5d27966 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -19,7 +19,6 @@
 #define LOG_TAG "MediaScannerJNI"
 #include <utils/Log.h>
 #include <utils/threads.h>
-#include <utils/Unicode.h>
 #include <media/mediascanner.h>
 #include <media/stagefright/StagefrightMediaScanner.h>
 
@@ -57,6 +56,53 @@
     return OK;
 }
 
+// stolen from dalvik/vm/checkJni.cpp
+static bool isValidUtf8(const char* bytes) {
+    while (*bytes != '\0') {
+        unsigned char utf8 = *(bytes++);
+        // Switch on the high four bits.
+        switch (utf8 >> 4) {
+        case 0x00:
+        case 0x01:
+        case 0x02:
+        case 0x03:
+        case 0x04:
+        case 0x05:
+        case 0x06:
+        case 0x07:
+            // Bit pattern 0xxx. No need for any extra bytes.
+            break;
+        case 0x08:
+        case 0x09:
+        case 0x0a:
+        case 0x0b:
+        case 0x0f:
+            /*
+             * Bit pattern 10xx or 1111, which are illegal start bytes.
+             * Note: 1111 is valid for normal UTF-8, but not the
+             * modified UTF-8 used here.
+             */
+            return false;
+        case 0x0e:
+            // Bit pattern 1110, so there are two additional bytes.
+            utf8 = *(bytes++);
+            if ((utf8 & 0xc0) != 0x80) {
+                return false;
+            }
+            // Fall through to take care of the final byte.
+        case 0x0c:
+        case 0x0d:
+            // Bit pattern 110x, so there is one additional byte.
+            utf8 = *(bytes++);
+            if ((utf8 & 0xc0) != 0x80) {
+                return false;
+            }
+            break;
+        }
+    }
+    return true;
+}
+
 class MyMediaScannerClient : public MediaScannerClient
 {
 public:
@@ -124,11 +170,8 @@
             mEnv->ExceptionClear();
             return NO_MEMORY;
         }
-
-        // Check if the value is valid UTF-8 string and replace
-        // any un-printable characters with '?' when it's not.
         char *cleaned = NULL;
-        if (utf8_length(value) == -1) {
+        if (!isValidUtf8(value)) {
             cleaned = strdup(value);
             char *chp = cleaned;
             char ch;
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
new file mode 100644
index 0000000..f993ab5
--- /dev/null
+++ b/packages/Shell/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Shell
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
new file mode 100644
index 0000000..b42db45
--- /dev/null
+++ b/packages/Shell/AndroidManifest.xml
@@ -0,0 +1,74 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.shell"
+        coreApp="true"
+        android:sharedUserId="android.uid.shell"
+        >
+
+    <!-- Standard permissions granted to the shell. -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+    <uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
+    <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <!-- System tool permissions granted to the shell. -->
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
+    <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
+    <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <!-- Development tool permissions granted to the shell. -->
+    <uses-permission android:name="android.permission.SET_DEBUG_APP" />
+    <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
+    <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+    <!-- Internal permissions granted to the shell. -->
+    <uses-permission android:name="android.permission.FORCE_BACK" />
+    <uses-permission android:name="android.permission.BATTERY_STATS" />
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
+    <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />
+    <uses-permission android:name="android.permission.READ_INPUT_STATE" />
+    <uses-permission android:name="android.permission.SET_ORIENTATION" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+    <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
+    <uses-permission android:name="android.permission.BACKUP" />
+    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
+    <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
+    <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
+    <uses-permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" />
+    <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+    <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
+    
+    <application android:hasCode="false" android:label="@string/app_label">
+    </application>
+</manifest>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
new file mode 100644
index 0000000..50610d5
--- /dev/null
+++ b/packages/Shell/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_label">Shell</string>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 9a1e38d..e79b2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -45,6 +45,8 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
@@ -162,7 +164,7 @@
             if (convertView == null) {
                 convertView = createView(parent);
             }
-            ViewHolder holder = (ViewHolder) convertView.getTag();
+            final ViewHolder holder = (ViewHolder) convertView.getTag();
 
             // index is reverse since most recent appears at the bottom...
             final int index = mRecentTaskDescriptions.size() - position - 1;
@@ -191,24 +193,49 @@
                             holder.calloutLine.setTranslationY(0f);
                         }
                     }
-                    mItemToAnimateInWhenWindowAnimationIsFinished = holder;
-                    final int translation = -getResources().getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_icon_translate_distance);
-                    final Configuration config = getResources().getConfiguration();
-                    if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                        holder.iconView.setAlpha(0f);
-                        holder.iconView.setTranslationX(translation);
-                        holder.labelView.setAlpha(0f);
-                        holder.labelView.setTranslationX(translation);
-                        holder.calloutLine.setAlpha(0f);
-                        holder.calloutLine.setTranslationX(translation);
-                    } else {
-                        holder.iconView.setAlpha(0f);
-                        holder.iconView.setTranslationY(translation);
-                    }
-                    if (!mWaitingForWindowAnimation) {
-                        animateInIconOfFirstTask();
-                    }
+                    mItemToAnimateInWhenWindowAnimationIsFinished = null;
+
+                    final ViewTreeObserver observer = getViewTreeObserver();
+                    final OnGlobalLayoutListener animateFirstIcon = new OnGlobalLayoutListener() {
+                        public void onGlobalLayout() {
+                            if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
+                                holder.iconView.setAlpha(1f);
+                                holder.iconView.setTranslationX(0f);
+                                holder.iconView.setTranslationY(0f);
+                                holder.labelView.setAlpha(1f);
+                                holder.labelView.setTranslationX(0f);
+                                holder.labelView.setTranslationY(0f);
+                                if (holder.calloutLine != null) {
+                                    holder.calloutLine.setAlpha(1f);
+                                    holder.calloutLine.setTranslationX(0f);
+                                    holder.calloutLine.setTranslationY(0f);
+                                }
+                            }
+                            mItemToAnimateInWhenWindowAnimationIsFinished = holder;
+                            int translation = -getResources().getDimensionPixelSize(
+                                    R.dimen.status_bar_recents_app_icon_translate_distance);
+                            final Configuration config = getResources().getConfiguration();
+                            if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                                if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                                    translation = -translation;
+                                }
+                                holder.iconView.setAlpha(0f);
+                                holder.iconView.setTranslationX(translation);
+                                holder.labelView.setAlpha(0f);
+                                holder.labelView.setTranslationX(translation);
+                                holder.calloutLine.setAlpha(0f);
+                                holder.calloutLine.setTranslationX(translation);
+                            } else {
+                                holder.iconView.setAlpha(0f);
+                                holder.iconView.setTranslationY(translation);
+                            }
+                            if (!mWaitingForWindowAnimation) {
+                                animateInIconOfFirstTask();
+                            }
+                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                        }
+                    };
+                    observer.addOnGlobalLayoutListener(animateFirstIcon);
                 }
             }
 
@@ -682,8 +709,12 @@
                     | Intent.FLAG_ACTIVITY_TASK_ON_HOME
                     | Intent.FLAG_ACTIVITY_NEW_TASK);
             if (DEBUG) Log.v(TAG, "Starting activity " + intent);
-            context.startActivityAsUser(intent, opts,
-                    new UserHandle(UserHandle.USER_CURRENT));
+            try {
+                context.startActivityAsUser(intent, opts,
+                        new UserHandle(UserHandle.USER_CURRENT));
+            } catch (SecurityException e) {
+                Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
+            }
         }
         if (usingDrawingCache) {
             holder.thumbnailViewImage.setDrawingCacheEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 280b368..ddfaad5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -45,6 +45,7 @@
 import android.os.Process;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -86,6 +87,8 @@
  */
 class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
         SaveImageInBackgroundData> {
+    private static final String TAG = "SaveImageInBackgroundTask";
+
     private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
     private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
     private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
@@ -138,6 +141,7 @@
                             (shortSide - mImageHeight) / 2);
         c.drawBitmap(data.image, matrix, paint);
         c.drawColor(0x40FFFFFF);
+        c.setBitmap(null);
 
         Bitmap croppedIcon = Bitmap.createScaledBitmap(preview, iconSize, iconSize, true);
 
@@ -167,6 +171,8 @@
         mNotificationBuilder.setLargeIcon(croppedIcon);
         // But we still don't set it for the expanded view, allowing the smallIcon to show here.
         mNotificationStyle.bigLargeIcon(null);
+
+        Log.d(TAG, "SaveImageInBackgroundTask constructor");
     }
 
     @Override
@@ -174,6 +180,7 @@
         if (params.length != 1) return null;
         if (isCancelled()) {
             params[0].clearImage();
+            Log.d(TAG, "doInBackground cancelled");
             return null;
         }
 
@@ -238,6 +245,7 @@
             // mounted
             params[0].clearImage();
             params[0].result = 1;
+            Log.d(TAG, "doInBackground failed");
         }
 
         // Recycle the bitmap data
@@ -245,6 +253,7 @@
             image.recycle();
         }
 
+        Log.d(TAG, "doInBackground complete");
         return params[0];
     }
 
@@ -253,6 +262,7 @@
         if (isCancelled()) {
             params.finisher.run();
             params.clearImage();
+            Log.d(TAG, "onPostExecute cancelled");
             return;
         }
 
@@ -280,6 +290,7 @@
             mNotificationManager.notify(mNotificationId, n);
         }
         params.finisher.run();
+        Log.d(TAG, "onPostExecute complete");
     }
 }
 
@@ -290,6 +301,8 @@
  *     type of gallery?
  */
 class GlobalScreenshot {
+    private static final String TAG = "GlobalScreenshot";
+
     private static final int SCREENSHOT_NOTIFICATION_ID = 789;
     private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
     private static final int SCREENSHOT_DROP_IN_DURATION = 430;
@@ -381,12 +394,15 @@
         // Setup the Camera shutter sound
         mCameraSound = new MediaActionSound();
         mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+
+        Log.d(TAG, "GlobalScreenshot constructor");
     }
 
     /**
      * Creates a new worker thread and saves the screenshot to the media store.
      */
     private void saveScreenshotInWorkerThread(Runnable finisher) {
+        Log.d(TAG, "saveScreenshotInWorkerThread");
         SaveImageInBackgroundData data = new SaveImageInBackgroundData();
         data.context = mContext;
         data.image = mScreenBitmap;
@@ -394,6 +410,7 @@
         data.finisher = finisher;
         if (mSaveInBgTask != null) {
             mSaveInBgTask.cancel(false);
+            Log.d(TAG, "saveScreenshotInWorkerThread cancel");
         }
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
                 SCREENSHOT_NOTIFICATION_ID).execute(data);
@@ -418,6 +435,8 @@
      * Takes a screenshot of the current display and shows an animation.
      */
     void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+        Log.d(TAG, "takeScreenshot");
+
         // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
         // only in the natural orientation of the device :!)
         mDisplay.getRealMetrics(mDisplayMetrics);
@@ -431,6 +450,8 @@
             mDisplayMatrix.mapPoints(dims);
             dims[0] = Math.abs(dims[0]);
             dims[1] = Math.abs(dims[1]);
+
+            Log.d(TAG, "takeScreenshot requiresRotation");
         }
 
         // Take the screenshot
@@ -438,6 +459,7 @@
         if (mScreenBitmap == null) {
             notifyScreenshotError(mContext, mNotificationManager);
             finisher.run();
+            Log.d(TAG, "takeScreenshot null bitmap");
             return;
         }
 
@@ -451,7 +473,10 @@
             c.translate(-dims[0] / 2, -dims[1] / 2);
             c.drawBitmap(mScreenBitmap, 0, 0, null);
             c.setBitmap(null);
+            // Recycle the previous bitmap
+            mScreenBitmap.recycle();
             mScreenBitmap = ss;
+            Log.d(TAG, "takeScreenshot rotation bitmap created");
         }
 
         // Optimizations
@@ -461,6 +486,7 @@
         // Start the post-screenshot animation
         startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
                 statusBarVisible, navBarVisible);
+        Log.d(TAG, "takeScreenshot startedAnimation");
     }
 
 
@@ -469,6 +495,7 @@
      */
     private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,
             boolean navBarVisible) {
+        Log.d(TAG, "startAnimation");
         // Add the view for the animation
         mScreenshotView.setImageBitmap(mScreenBitmap);
         mScreenshotLayout.requestFocus();
@@ -477,9 +504,11 @@
         if (mScreenshotAnimation != null) {
             mScreenshotAnimation.end();
             mScreenshotAnimation.removeAllListeners();
+            Log.d(TAG, "startAnimation reset previous animations");
         }
 
         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+        Log.d(TAG, "startAnimation layout added to WM");
         ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
         ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
                 statusBarVisible, navBarVisible);
@@ -495,6 +524,7 @@
                 // Clear any references to the bitmap
                 mScreenBitmap = null;
                 mScreenshotView.setImageBitmap(null);
+                Log.d(TAG, "startAnimation onAnimationEnd");
             }
         });
         mScreenshotLayout.post(new Runnable() {
@@ -506,6 +536,7 @@
                 mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                 mScreenshotView.buildLayer();
                 mScreenshotAnimation.start();
+                Log.d(TAG, "startAnimation post runnable");
             }
         });
     }
@@ -643,6 +674,7 @@
     }
 
     static void notifyScreenshotError(Context context, NotificationManager nManager) {
+        Log.d(TAG, "notifyScreenshotError");
         Resources r = context.getResources();
 
         // Clear all existing notification, compose the new notification and show it
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 456b5fa..1954af8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.util.Log;
 
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
@@ -37,12 +38,15 @@
                     final Messenger callback = msg.replyTo;
                     if (mScreenshot == null) {
                         mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+                        Log.d(TAG, "Global screenshot initialized");
                     }
+                    Log.d(TAG, "Global screenshot captured");
                     mScreenshot.takeScreenshot(new Runnable() {
                         @Override public void run() {
                             Message reply = Message.obtain(null, 1);
                             try {
                                 callback.send(reply);
+                                Log.d(TAG, "Global screenshot completed");
                             } catch (RemoteException e) {
                             }
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3bac146..f941f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -597,6 +597,10 @@
                     y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
                             + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
                 }
+                if (mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
+                    x = dm.widthPixels - x - res
+                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+                }
 
                 ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
                         getStatusBarView(),
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9d0903c..9cb54a9 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -84,7 +84,6 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
-import android.view.WindowOrientationListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -555,8 +554,8 @@
     }
     
     class MyOrientationListener extends WindowOrientationListener {
-        MyOrientationListener(Context context) {
-            super(context);
+        MyOrientationListener(Context context, Handler handler) {
+            super(context, handler);
         }
         
         @Override
@@ -854,7 +853,7 @@
             mKeyguardMediator = new KeyguardViewMediator(context, null);
         }
         mHandler = new PolicyHandler();
-        mOrientationListener = new MyOrientationListener(mContext);
+        mOrientationListener = new MyOrientationListener(mContext, mHandler);
         try {
             mOrientationListener.setCurrentRotation(windowManager.getRotation());
         } catch (RemoteException ex) { }
@@ -3760,13 +3759,16 @@
     }
 
     BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
                 mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
             }
             updateRotation(true);
-            updateOrientationListenerLp();
+            synchronized (mLock) {
+                updateOrientationListenerLp();
+            }
         }
     };
 
diff --git a/core/java/android/view/WindowOrientationListener.java b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
similarity index 65%
rename from core/java/android/view/WindowOrientationListener.java
rename to policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
index bf77c67..0c77556 100644
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package android.view;
+package com.android.internal.policy.impl;
 
 import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.os.Handler;
 import android.os.SystemProperties;
 import android.util.FloatMath;
 import android.util.Log;
@@ -47,26 +48,31 @@
 
     private static final boolean USE_GRAVITY_SENSOR = false;
 
+    private Handler mHandler;
     private SensorManager mSensorManager;
     private boolean mEnabled;
     private int mRate;
     private Sensor mSensor;
     private SensorEventListenerImpl mSensorEventListener;
-    int mCurrentRotation = -1;
+    private int mCurrentRotation = -1;
+
+    private final Object mLock = new Object();
 
     /**
      * Creates a new WindowOrientationListener.
      * 
      * @param context for the WindowOrientationListener.
+     * @param handler Provides the Looper for receiving sensor updates.
      */
-    public WindowOrientationListener(Context context) {
-        this(context, SensorManager.SENSOR_DELAY_UI);
+    public WindowOrientationListener(Context context, Handler handler) {
+        this(context, handler, SensorManager.SENSOR_DELAY_UI);
     }
     
     /**
      * Creates a new WindowOrientationListener.
      * 
      * @param context for the WindowOrientationListener.
+     * @param handler Provides the Looper for receiving sensor updates.
      * @param rate at which sensor events are processed (see also
      * {@link android.hardware.SensorManager SensorManager}). Use the default
      * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
@@ -74,33 +80,36 @@
      *
      * This constructor is private since no one uses it.
      */
-    private WindowOrientationListener(Context context, int rate) {
+    private WindowOrientationListener(Context context, Handler handler, int rate) {
+        mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
         mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
                 ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
         if (mSensor != null) {
             // Create listener only if sensors do exist
-            mSensorEventListener = new SensorEventListenerImpl(this);
+            mSensorEventListener = new SensorEventListenerImpl();
         }
     }
 
     /**
      * Enables the WindowOrientationListener so it will monitor the sensor and call
-     * {@link #onOrientationChanged} when the device orientation changes.
+     * {@link #onProposedRotationChanged(int)} when the device orientation changes.
      */
     public void enable() {
-        if (mSensor == null) {
-            Log.w(TAG, "Cannot detect sensors. Not enabled");
-            return;
-        }
-        if (mEnabled == false) {
-            if (LOG) {
-                Log.d(TAG, "WindowOrientationListener enabled");
+        synchronized (mLock) {
+            if (mSensor == null) {
+                Log.w(TAG, "Cannot detect sensors. Not enabled");
+                return;
             }
-            mSensorEventListener.reset();
-            mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
-            mEnabled = true;
+            if (mEnabled == false) {
+                if (LOG) {
+                    Log.d(TAG, "WindowOrientationListener enabled");
+                }
+                mSensorEventListener.resetLocked();
+                mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
+                mEnabled = true;
+            }
         }
     }
 
@@ -108,16 +117,18 @@
      * Disables the WindowOrientationListener.
      */
     public void disable() {
-        if (mSensor == null) {
-            Log.w(TAG, "Cannot detect sensors. Invalid disable");
-            return;
-        }
-        if (mEnabled == true) {
-            if (LOG) {
-                Log.d(TAG, "WindowOrientationListener disabled");
+        synchronized (mLock) {
+            if (mSensor == null) {
+                Log.w(TAG, "Cannot detect sensors. Invalid disable");
+                return;
             }
-            mSensorManager.unregisterListener(mSensorEventListener);
-            mEnabled = false;
+            if (mEnabled == true) {
+                if (LOG) {
+                    Log.d(TAG, "WindowOrientationListener disabled");
+                }
+                mSensorManager.unregisterListener(mSensorEventListener);
+                mEnabled = false;
+            }
         }
     }
 
@@ -127,7 +138,9 @@
      * @param rotation The current rotation.
      */
     public void setCurrentRotation(int rotation) {
-        mCurrentRotation = rotation;
+        synchronized (mLock) {
+            mCurrentRotation = rotation;
+        }
     }
 
     /**
@@ -139,17 +152,21 @@
      * @return The proposed rotation, or -1 if unknown.
      */
     public int getProposedRotation() {
-        if (mEnabled) {
-            return mSensorEventListener.getProposedRotation();
+        synchronized (mLock) {
+            if (mEnabled) {
+                return mSensorEventListener.getProposedRotationLocked();
+            }
+            return -1;
         }
-        return -1;
     }
 
     /**
      * Returns true if sensor is enabled and false otherwise
      */
     public boolean canDetectOrientation() {
-        return mSensor != null;
+        synchronized (mLock) {
+            return mSensor != null;
+        }
     }
 
     /**
@@ -160,7 +177,7 @@
      * uncertain to being certain again, even if it is the same orientation as before.
      *
      * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
-     * @see Surface
+     * @see android.view.Surface
      */
     public abstract void onProposedRotationChanged(int rotation);
 
@@ -202,7 +219,7 @@
      * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
      * signal processing background.
      */
-    static final class SensorEventListenerImpl implements SensorEventListener {
+    final class SensorEventListenerImpl implements SensorEventListener {
         // We work with all angles in degrees in this class.
         private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
 
@@ -214,8 +231,6 @@
         private static final int ACCELEROMETER_DATA_Y = 1;
         private static final int ACCELEROMETER_DATA_Z = 2;
 
-        private final WindowOrientationListener mOrientationListener;
-
         // The minimum amount of time that a predicted rotation must be stable before it
         // is accepted as a valid rotation proposal.  This value can be quite small because
         // the low-pass filter already suppresses most of the noise so we're really just
@@ -320,7 +335,7 @@
         // facing up (resting on a table).
         // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
         // how close to vertical the device must be in order to change orientation.
-        private static final int[][] TILT_TOLERANCE = new int[][] {
+        private final int[][] TILT_TOLERANCE = new int[][] {
             /* ROTATION_0   */ { -25, 70 },
             /* ROTATION_90  */ { -25, 65 },
             /* ROTATION_180 */ { -25, 60 },
@@ -362,12 +377,7 @@
         private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
         private int mTiltHistoryIndex;
 
-        public SensorEventListenerImpl(WindowOrientationListener orientationListener) {
-            mOrientationListener = orientationListener;
-            reset();
-        }
-
-        public int getProposedRotation() {
+        public int getProposedRotationLocked() {
             return mProposedRotation;
         }
 
@@ -377,179 +387,187 @@
 
         @Override
         public void onSensorChanged(SensorEvent event) {
-            // The vector given in the SensorEvent points straight up (towards the sky) under ideal
-            // conditions (the phone is not accelerating).  I'll call this up vector elsewhere.
-            float x = event.values[ACCELEROMETER_DATA_X];
-            float y = event.values[ACCELEROMETER_DATA_Y];
-            float z = event.values[ACCELEROMETER_DATA_Z];
+            int proposedRotation;
+            int oldProposedRotation;
 
-            if (LOG) {
-                Slog.v(TAG, "Raw acceleration vector: "
-                        + "x=" + x + ", y=" + y + ", z=" + z
-                        + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
-            }
+            synchronized (mLock) {
+                // The vector given in the SensorEvent points straight up (towards the sky) under
+                // ideal conditions (the phone is not accelerating).  I'll call this up vector
+                // elsewhere.
+                float x = event.values[ACCELEROMETER_DATA_X];
+                float y = event.values[ACCELEROMETER_DATA_Y];
+                float z = event.values[ACCELEROMETER_DATA_Z];
 
-            // Apply a low-pass filter to the acceleration up vector in cartesian space.
-            // Reset the orientation listener state if the samples are too far apart in time
-            // or when we see values of (0, 0, 0) which indicates that we polled the
-            // accelerometer too soon after turning it on and we don't have any data yet.
-            final long now = event.timestamp;
-            final long then = mLastFilteredTimestampNanos;
-            final float timeDeltaMS = (now - then) * 0.000001f;
-            final boolean skipSample;
-            if (now < then
-                    || now > then + MAX_FILTER_DELTA_TIME_NANOS
-                    || (x == 0 && y == 0 && z == 0)) {
                 if (LOG) {
-                    Slog.v(TAG, "Resetting orientation listener.");
-                }
-                reset();
-                skipSample = true;
-            } else {
-                final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
-                x = alpha * (x - mLastFilteredX) + mLastFilteredX;
-                y = alpha * (y - mLastFilteredY) + mLastFilteredY;
-                z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
-                if (LOG) {
-                    Slog.v(TAG, "Filtered acceleration vector: "
+                    Slog.v(TAG, "Raw acceleration vector: "
                             + "x=" + x + ", y=" + y + ", z=" + z
                             + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
                 }
-                skipSample = false;
-            }
-            mLastFilteredTimestampNanos = now;
-            mLastFilteredX = x;
-            mLastFilteredY = y;
-            mLastFilteredZ = z;
 
-            boolean isAccelerating = false;
-            boolean isFlat = false;
-            boolean isSwinging = false;
-            if (!skipSample) {
-                // Calculate the magnitude of the acceleration vector.
-                final float magnitude = FloatMath.sqrt(x * x + y * y + z * z);
-                if (magnitude < NEAR_ZERO_MAGNITUDE) {
+                // Apply a low-pass filter to the acceleration up vector in cartesian space.
+                // Reset the orientation listener state if the samples are too far apart in time
+                // or when we see values of (0, 0, 0) which indicates that we polled the
+                // accelerometer too soon after turning it on and we don't have any data yet.
+                final long now = event.timestamp;
+                final long then = mLastFilteredTimestampNanos;
+                final float timeDeltaMS = (now - then) * 0.000001f;
+                final boolean skipSample;
+                if (now < then
+                        || now > then + MAX_FILTER_DELTA_TIME_NANOS
+                        || (x == 0 && y == 0 && z == 0)) {
                     if (LOG) {
-                        Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
+                        Slog.v(TAG, "Resetting orientation listener.");
                     }
-                    clearPredictedRotation();
+                    resetLocked();
+                    skipSample = true;
                 } else {
-                    // Determine whether the device appears to be undergoing external acceleration.
-                    if (isAccelerating(magnitude)) {
-                        isAccelerating = true;
-                        mAccelerationTimestampNanos = now;
+                    final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
+                    x = alpha * (x - mLastFilteredX) + mLastFilteredX;
+                    y = alpha * (y - mLastFilteredY) + mLastFilteredY;
+                    z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
+                    if (LOG) {
+                        Slog.v(TAG, "Filtered acceleration vector: "
+                                + "x=" + x + ", y=" + y + ", z=" + z
+                                + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
                     }
+                    skipSample = false;
+                }
+                mLastFilteredTimestampNanos = now;
+                mLastFilteredX = x;
+                mLastFilteredY = y;
+                mLastFilteredZ = z;
 
-                    // Calculate the tilt angle.
-                    // This is the angle between the up vector and the x-y plane (the plane of
-                    // the screen) in a range of [-90, 90] degrees.
-                    //   -90 degrees: screen horizontal and facing the ground (overhead)
-                    //     0 degrees: screen vertical
-                    //    90 degrees: screen horizontal and facing the sky (on table)
-                    final int tiltAngle = (int) Math.round(
-                            Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
-                    addTiltHistoryEntry(now, tiltAngle);
-
-                    // Determine whether the device appears to be flat or swinging.
-                    if (isFlat(now)) {
-                        isFlat = true;
-                        mFlatTimestampNanos = now;
-                    }
-                    if (isSwinging(now, tiltAngle)) {
-                        isSwinging = true;
-                        mSwingTimestampNanos = now;
-                    }
-
-                    // If the tilt angle is too close to horizontal then we cannot determine
-                    // the orientation angle of the screen.
-                    if (Math.abs(tiltAngle) > MAX_TILT) {
+                boolean isAccelerating = false;
+                boolean isFlat = false;
+                boolean isSwinging = false;
+                if (!skipSample) {
+                    // Calculate the magnitude of the acceleration vector.
+                    final float magnitude = FloatMath.sqrt(x * x + y * y + z * z);
+                    if (magnitude < NEAR_ZERO_MAGNITUDE) {
                         if (LOG) {
-                            Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
-                                    + "tiltAngle=" + tiltAngle);
+                            Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
                         }
-                        clearPredictedRotation();
+                        clearPredictedRotationLocked();
                     } else {
-                        // Calculate the orientation angle.
-                        // This is the angle between the x-y projection of the up vector onto
-                        // the +y-axis, increasing clockwise in a range of [0, 360] degrees.
-                        int orientationAngle = (int) Math.round(
-                                -Math.atan2(-x, y) * RADIANS_TO_DEGREES);
-                        if (orientationAngle < 0) {
-                            // atan2 returns [-180, 180]; normalize to [0, 360]
-                            orientationAngle += 360;
+                        // Determine whether the device appears to be undergoing external
+                        // acceleration.
+                        if (isAcceleratingLocked(magnitude)) {
+                            isAccelerating = true;
+                            mAccelerationTimestampNanos = now;
                         }
 
-                        // Find the nearest rotation.
-                        int nearestRotation = (orientationAngle + 45) / 90;
-                        if (nearestRotation == 4) {
-                            nearestRotation = 0;
+                        // Calculate the tilt angle.
+                        // This is the angle between the up vector and the x-y plane (the plane of
+                        // the screen) in a range of [-90, 90] degrees.
+                        //   -90 degrees: screen horizontal and facing the ground (overhead)
+                        //     0 degrees: screen vertical
+                        //    90 degrees: screen horizontal and facing the sky (on table)
+                        final int tiltAngle = (int) Math.round(
+                                Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
+                        addTiltHistoryEntryLocked(now, tiltAngle);
+
+                        // Determine whether the device appears to be flat or swinging.
+                        if (isFlatLocked(now)) {
+                            isFlat = true;
+                            mFlatTimestampNanos = now;
+                        }
+                        if (isSwingingLocked(now, tiltAngle)) {
+                            isSwinging = true;
+                            mSwingTimestampNanos = now;
                         }
 
-                        // Determine the predicted orientation.
-                        if (isTiltAngleAcceptable(nearestRotation, tiltAngle)
-                                && isOrientationAngleAcceptable(nearestRotation,
-                                        orientationAngle)) {
-                            updatePredictedRotation(now, nearestRotation);
+                        // If the tilt angle is too close to horizontal then we cannot determine
+                        // the orientation angle of the screen.
+                        if (Math.abs(tiltAngle) > MAX_TILT) {
                             if (LOG) {
-                                Slog.v(TAG, "Predicted: "
-                                        + "tiltAngle=" + tiltAngle
-                                        + ", orientationAngle=" + orientationAngle
-                                        + ", predictedRotation=" + mPredictedRotation
-                                        + ", predictedRotationAgeMS="
-                                                + ((now - mPredictedRotationTimestampNanos)
-                                                        * 0.000001f));
+                                Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
+                                        + "tiltAngle=" + tiltAngle);
                             }
+                            clearPredictedRotationLocked();
                         } else {
-                            if (LOG) {
-                                Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
-                                        + "tiltAngle=" + tiltAngle
-                                        + ", orientationAngle=" + orientationAngle);
+                            // Calculate the orientation angle.
+                            // This is the angle between the x-y projection of the up vector onto
+                            // the +y-axis, increasing clockwise in a range of [0, 360] degrees.
+                            int orientationAngle = (int) Math.round(
+                                    -Math.atan2(-x, y) * RADIANS_TO_DEGREES);
+                            if (orientationAngle < 0) {
+                                // atan2 returns [-180, 180]; normalize to [0, 360]
+                                orientationAngle += 360;
                             }
-                            clearPredictedRotation();
+
+                            // Find the nearest rotation.
+                            int nearestRotation = (orientationAngle + 45) / 90;
+                            if (nearestRotation == 4) {
+                                nearestRotation = 0;
+                            }
+
+                            // Determine the predicted orientation.
+                            if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
+                                    && isOrientationAngleAcceptableLocked(nearestRotation,
+                                            orientationAngle)) {
+                                updatePredictedRotationLocked(now, nearestRotation);
+                                if (LOG) {
+                                    Slog.v(TAG, "Predicted: "
+                                            + "tiltAngle=" + tiltAngle
+                                            + ", orientationAngle=" + orientationAngle
+                                            + ", predictedRotation=" + mPredictedRotation
+                                            + ", predictedRotationAgeMS="
+                                                    + ((now - mPredictedRotationTimestampNanos)
+                                                            * 0.000001f));
+                                }
+                            } else {
+                                if (LOG) {
+                                    Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
+                                            + "tiltAngle=" + tiltAngle
+                                            + ", orientationAngle=" + orientationAngle);
+                                }
+                                clearPredictedRotationLocked();
+                            }
                         }
                     }
                 }
-            }
 
-            // Determine new proposed rotation.
-            final int oldProposedRotation = mProposedRotation;
-            if (mPredictedRotation < 0 || isPredictedRotationAcceptable(now)) {
-                mProposedRotation = mPredictedRotation;
-            }
+                // Determine new proposed rotation.
+                oldProposedRotation = mProposedRotation;
+                if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
+                    mProposedRotation = mPredictedRotation;
+                }
+                proposedRotation = mProposedRotation;
 
-            // Write final statistics about where we are in the orientation detection process.
-            if (LOG) {
-                Slog.v(TAG, "Result: currentRotation=" + mOrientationListener.mCurrentRotation
-                        + ", proposedRotation=" + mProposedRotation
-                        + ", predictedRotation=" + mPredictedRotation
-                        + ", timeDeltaMS=" + timeDeltaMS
-                        + ", isAccelerating=" + isAccelerating
-                        + ", isFlat=" + isFlat
-                        + ", isSwinging=" + isSwinging
-                        + ", timeUntilSettledMS=" + remainingMS(now,
-                                mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
-                        + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
-                                mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
-                        + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
-                                mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
-                        + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
-                                mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
+                // Write final statistics about where we are in the orientation detection process.
+                if (LOG) {
+                    Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation
+                            + ", proposedRotation=" + proposedRotation
+                            + ", predictedRotation=" + mPredictedRotation
+                            + ", timeDeltaMS=" + timeDeltaMS
+                            + ", isAccelerating=" + isAccelerating
+                            + ", isFlat=" + isFlat
+                            + ", isSwinging=" + isSwinging
+                            + ", timeUntilSettledMS=" + remainingMS(now,
+                                    mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
+                            + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
+                                    mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
+                            + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
+                                    mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
+                            + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
+                                    mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
+                }
             }
 
             // Tell the listener.
-            if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0) {
+            if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
                 if (LOG) {
-                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + mProposedRotation
+                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + proposedRotation
                             + ", oldProposedRotation=" + oldProposedRotation);
                 }
-                mOrientationListener.onProposedRotationChanged(mProposedRotation);
+                onProposedRotationChanged(proposedRotation);
             }
         }
 
         /**
          * Returns true if the tilt angle is acceptable for a given predicted rotation.
          */
-        private boolean isTiltAngleAcceptable(int rotation, int tiltAngle) {
+        private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
             return tiltAngle >= TILT_TOLERANCE[rotation][0]
                     && tiltAngle <= TILT_TOLERANCE[rotation][1];
         }
@@ -560,11 +578,11 @@
          * This function takes into account the gap between adjacent orientations
          * for hysteresis.
          */
-        private boolean isOrientationAngleAcceptable(int rotation, int orientationAngle) {
+        private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) {
             // If there is no current rotation, then there is no gap.
             // The gap is used only to introduce hysteresis among advertised orientation
             // changes to avoid flapping.
-            final int currentRotation = mOrientationListener.mCurrentRotation;
+            final int currentRotation = mCurrentRotation;
             if (currentRotation >= 0) {
                 // If the specified rotation is the same or is counter-clockwise adjacent
                 // to the current rotation, then we set a lower bound on the orientation angle.
@@ -611,7 +629,7 @@
          * Returns true if the predicted rotation is ready to be advertised as a
          * proposed rotation.
          */
-        private boolean isPredictedRotationAcceptable(long now) {
+        private boolean isPredictedRotationAcceptableLocked(long now) {
             // The predicted rotation must have settled long enough.
             if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
                 return false;
@@ -638,47 +656,47 @@
             return true;
         }
 
-        private void reset() {
+        private void resetLocked() {
             mLastFilteredTimestampNanos = Long.MIN_VALUE;
             mProposedRotation = -1;
             mFlatTimestampNanos = Long.MIN_VALUE;
             mSwingTimestampNanos = Long.MIN_VALUE;
             mAccelerationTimestampNanos = Long.MIN_VALUE;
-            clearPredictedRotation();
-            clearTiltHistory();
+            clearPredictedRotationLocked();
+            clearTiltHistoryLocked();
         }
 
-        private void clearPredictedRotation() {
+        private void clearPredictedRotationLocked() {
             mPredictedRotation = -1;
             mPredictedRotationTimestampNanos = Long.MIN_VALUE;
         }
 
-        private void updatePredictedRotation(long now, int rotation) {
+        private void updatePredictedRotationLocked(long now, int rotation) {
             if (mPredictedRotation != rotation) {
                 mPredictedRotation = rotation;
                 mPredictedRotationTimestampNanos = now;
             }
         }
 
-        private boolean isAccelerating(float magnitude) {
+        private boolean isAcceleratingLocked(float magnitude) {
             return magnitude < MIN_ACCELERATION_MAGNITUDE
                     || magnitude > MAX_ACCELERATION_MAGNITUDE;
         }
 
-        private void clearTiltHistory() {
+        private void clearTiltHistoryLocked() {
             mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
             mTiltHistoryIndex = 1;
         }
 
-        private void addTiltHistoryEntry(long now, float tilt) {
+        private void addTiltHistoryEntryLocked(long now, float tilt) {
             mTiltHistory[mTiltHistoryIndex] = tilt;
             mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now;
             mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE;
             mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE;
         }
 
-        private boolean isFlat(long now) {
-            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndex(i)) >= 0; ) {
+        private boolean isFlatLocked(long now) {
+            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
                 if (mTiltHistory[i] < FLAT_ANGLE) {
                     break;
                 }
@@ -690,8 +708,8 @@
             return false;
         }
 
-        private boolean isSwinging(long now, float tilt) {
-            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndex(i)) >= 0; ) {
+        private boolean isSwingingLocked(long now, float tilt) {
+            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
                 if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) {
                     break;
                 }
@@ -703,12 +721,12 @@
             return false;
         }
 
-        private int nextTiltHistoryIndex(int index) {
+        private int nextTiltHistoryIndexLocked(int index) {
             index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1;
             return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1;
         }
 
-        private static float remainingMS(long now, long until) {
+        private float remainingMS(long now, long until) {
             return now >= until ? 0 : (until - now) * 0.000001f;
         }
     }
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index e94d03c..a402642 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -149,6 +149,61 @@
         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
     }
 
+    public void systemReady() {
+        synchronized (this) {
+            boolean changed = false;
+            for (int i=0; i<mUidOps.size(); i++) {
+                HashMap<String, Ops> pkgs = mUidOps.valueAt(i);
+                Iterator<Ops> it = pkgs.values().iterator();
+                while (it.hasNext()) {
+                    Ops ops = it.next();
+                    int curUid;
+                    try {
+                        curUid = mContext.getPackageManager().getPackageUid(ops.packageName,
+                                UserHandle.getUserId(ops.uid));
+                    } catch (NameNotFoundException e) {
+                        curUid = -1;
+                    }
+                    if (curUid != ops.uid) {
+                        Slog.i(TAG, "Pruning old package " + ops.packageName
+                                + "/" + ops.uid + ": new uid=" + curUid);
+                        it.remove();
+                        changed = true;
+                    }
+                }
+                if (pkgs.size() <= 0) {
+                    mUidOps.removeAt(i);
+                }
+            }
+            if (changed) {
+                scheduleWriteLocked();
+            }
+        }
+    }
+
+    public void packageRemoved(int uid, String packageName) {
+        synchronized (this) {
+            HashMap<String, Ops> pkgs = mUidOps.get(uid);
+            if (pkgs != null) {
+                if (pkgs.remove(packageName) != null) {
+                    if (pkgs.size() <= 0) {
+                        mUidOps.remove(uid);
+                    }
+                    scheduleWriteLocked();
+                }
+            }
+        }
+    }
+
+    public void uidRemoved(int uid) {
+        synchronized (this) {
+            if (mUidOps.indexOfKey(uid) >= 0) {
+                mUidOps.remove(uid);
+                scheduleWriteLocked();
+            }
+        }
+    }
+
     public void shutdown() {
         Slog.w(TAG, "Writing app ops before shutdown...");
         boolean doWrite = false;
@@ -258,6 +313,25 @@
                         }
                         repCbs.addAll(cbs);
                     }
+                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                        // If going into the default mode, prune this op
+                        // if there is nothing else interesting in it.
+                        if (op.time == 0 && op.rejectTime == 0) {
+                            Ops ops = getOpsLocked(uid, packageName, false);
+                            if (ops != null) {
+                                ops.remove(op.op);
+                                if (ops.size() <= 0) {
+                                    HashMap<String, Ops> pkgOps = mUidOps.get(uid);
+                                    if (pkgOps != null) {
+                                        pkgOps.remove(ops.packageName);
+                                        if (pkgOps.size() <= 0) {
+                                            mUidOps.remove(uid);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
                     scheduleWriteNowLocked();
                 }
             }
@@ -368,6 +442,7 @@
             if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
                     + " package " + packageName);
             op.time = System.currentTimeMillis();
+            op.rejectTime = 0;
             return AppOpsManager.MODE_ALLOWED;
         }
     }
@@ -396,6 +471,7 @@
                     + " package " + packageName);
             if (op.nesting == 0) {
                 op.time = System.currentTimeMillis();
+                op.rejectTime = 0;
                 op.duration = -1;
             }
             op.nesting++;
@@ -415,6 +491,7 @@
             if (op.nesting <= 1) {
                 if (op.nesting == 1) {
                     op.duration = (int)(System.currentTimeMillis() - op.time);
+                    op.time += op.duration;
                 } else {
                     Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
                         + " code " + code + " time=" + op.time + " duration=" + op.duration
@@ -454,6 +531,11 @@
             pkgOps = new HashMap<String, Ops>();
             mUidOps.put(uid, pkgOps);
         }
+        if (uid == 0) {
+            packageName = "root";
+        } else if (uid == Process.SHELL_UID) {
+            packageName = "com.android.shell";
+        }
         Ops ops = pkgOps.get(packageName);
         if (ops == null) {
             if (!edit) {
@@ -461,23 +543,25 @@
             }
             // This is the first time we have seen this package name under this uid,
             // so let's make sure it is valid.
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                int pkgUid = -1;
+            if (uid != 0) {
+                final long ident = Binder.clearCallingIdentity();
                 try {
-                    pkgUid = mContext.getPackageManager().getPackageUid(packageName,
-                            UserHandle.getUserId(uid));
-                } catch (NameNotFoundException e) {
+                    int pkgUid = -1;
+                    try {
+                        pkgUid = mContext.getPackageManager().getPackageUid(packageName,
+                                UserHandle.getUserId(uid));
+                    } catch (NameNotFoundException e) {
+                    }
+                    if (pkgUid != uid) {
+                        // Oops!  The package name is not valid for the uid they are calling
+                        // under.  Abort.
+                        Slog.w(TAG, "Bad call: specified package " + packageName
+                                + " under uid " + uid + " but it is really " + pkgUid);
+                        return null;
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
-                if (pkgUid != uid) {
-                    // Oops!  The package name is not valid for the uid they are calling
-                    // under.  Abort.
-                    Slog.w(TAG, "Bad call: specified package " + packageName
-                            + " under uid " + uid + " but it is really " + pkgUid);
-                    return null;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
             }
             ops = new Ops(packageName, uid);
             pkgOps.put(packageName, ops);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 88ea1f1..dfde692 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -133,7 +133,7 @@
 
 class BackupManagerService extends IBackupManager.Stub {
     private static final String TAG = "BackupManagerService";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
     private static final boolean MORE_DEBUG = false;
 
     // Name and current contents version of the full-backup manifest file
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fb81391..6efe4c5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -200,6 +200,7 @@
     private int mDefaultConnectionSequence = 0;
 
     private Object mDnsLock = new Object();
+    private int mNumDnsEntries;
     private boolean mDnsOverridden = false;
 
     private boolean mTestMode;
@@ -2479,6 +2480,17 @@
         try {
             mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
             mNetd.setDefaultInterfaceForDns(iface);
+            for (InetAddress dns : dnses) {
+                ++last;
+                String key = "net.dns" + last;
+                String value = dns.getHostAddress();
+                SystemProperties.set(key, value);
+            }
+            for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+                String key = "net.dns" + i;
+                SystemProperties.set(key, "");
+            }
+            mNumDnsEntries = last;
         } catch (Exception e) {
             if (DBG) loge("exception setting default dns interface: " + e);
         }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 6a62809..18b4ec1 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1889,7 +1889,7 @@
             mHandler.post(new Runnable() {
                 public void run() {
                     try {
-                        ActivityManagerNative.getDefault().switchUser(0);
+                        ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
                         ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
                                 .removeUser(userHandle);
                     } catch (RemoteException re) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 1a2c3de..13bf39f 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -235,6 +235,31 @@
                 }
             };
         }
+
+        public StatusBarNotification[] getArray(int count) {
+            if (count == 0) count = Archive.BUFFER_SIZE;
+            final StatusBarNotification[] a
+                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
+            Iterator<StatusBarNotification> iter = descendingIterator();
+            int i=0;
+            while (iter.hasNext() && i < count) {
+                a[i++] = iter.next();
+            }
+            return a;
+        }
+
+        public StatusBarNotification[] getArray(int count, String pkg, int userId) {
+            if (count == 0) count = Archive.BUFFER_SIZE;
+            final StatusBarNotification[] a
+                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
+            Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
+            int i=0;
+            while (iter.hasNext() && i < count) {
+                a[i++] = iter.next();
+            }
+            return a;
+        }
+
     }
 
     Archive mArchive = new Archive();
@@ -347,10 +372,9 @@
 
     public StatusBarNotification[] getActiveNotifications(String callingPkg) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
-                "NotificationManagerService");
+                "NotificationManagerService.getActiveNotifications");
 
         StatusBarNotification[] tmp = null;
-        int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
 
         if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
@@ -366,6 +390,22 @@
         return tmp;
     }
 
+    public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                "NotificationManagerService.getHistoricalNotifications");
+
+        StatusBarNotification[] tmp = null;
+        int uid = Binder.getCallingUid();
+
+        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                == AppOpsManager.MODE_ALLOWED) {
+            synchronized (mArchive) {
+                tmp = mArchive.getArray(count);
+            }
+        }
+        return tmp;
+    }
+
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index c37f51f..179db12 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -174,7 +174,7 @@
                 mMotionEventSequenceStarted = true;
             }
         } else {
-        // Wait for an enter hover event to start processing.
+            // Wait for an enter hover event to start processing.
             if (!mHoverEventSequenceStarted) {
                 if (motionEvent.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
                     return;
@@ -234,10 +234,14 @@
         if (DEBUG) {
             Slog.i(TAG, "Handling batched event: " + event + ", policyFlags: " + policyFlags);
         }
-        mPm.userActivity(event.getEventTime(), false);
-        MotionEvent transformedEvent = MotionEvent.obtain(event);
-        mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
-        transformedEvent.recycle();
+        // Since we do batch processing it is possible that by the time the
+        // next batch is processed the event handle had been set to null.
+        if (mEventHandler != null) {
+            mPm.userActivity(event.getEventTime(), false);
+            MotionEvent transformedEvent = MotionEvent.obtain(event);
+            mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
+            transformedEvent.recycle();
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index bb040bf..aadb790 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -123,6 +123,9 @@
     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
 
+    private static final ComponentName sFakeAccessibilityServiceComponentName =
+            new ComponentName("foo.bar", "FakeService");
+
     private static final String FUNCTION_DUMP = "dump";
 
     private static final char COMPONENT_NAME_SEPARATOR = ':';
@@ -157,8 +160,6 @@
 
     private final MainHandler mMainHandler;
 
-    private Service mUiAutomationService;
-
     private Service mQueryBridge;
 
     private AlertDialog mEnableTouchExplorationDialog;
@@ -167,6 +168,11 @@
 
     private boolean mHasInputFilter;
 
+    private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>();
+
+    private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
+            new ArrayList<AccessibilityServiceInfo>();
+
     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
             new RemoteCallbackList<IAccessibilityManagerClient>();
 
@@ -177,9 +183,6 @@
 
     private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
 
-    private final TempUserStateChangeMemento mTempStateChangeForCurrentUserMemento =
-            new TempUserStateChangeMemento();
-
     private int mCurrentUserId = UserHandle.USER_OWNER;
 
     private UserState getCurrentUserStateLocked() {
@@ -224,10 +227,11 @@
                         return;
                     }
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        populateInstalledAccessibilityServiceLocked(userState);
-                        manageServicesLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readConfigurationForUserStateLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             }
@@ -239,8 +243,8 @@
                     if (userId != mCurrentUserId) {
                         return;
                     }
-                    UserState state = getUserStateLocked(userId);
-                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
+                    UserState userState = getUserStateLocked(userId);
+                    Iterator<ComponentName> it = userState.mEnabledServices.iterator();
                     while (it.hasNext()) {
                         ComponentName comp = it.next();
                         String compPkg = comp.getPackageName();
@@ -249,13 +253,17 @@
                             // Update the enabled services setting.
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                                    state.mEnabledServices, userId);
+                                    userState.mEnabledServices, userId);
                             // Update the touch exploration granted services setting.
-                            state.mTouchExplorationGrantedServices.remove(comp);
+                            userState.mTouchExplorationGrantedServices.remove(comp);
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.
                                     TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                    state.mEnabledServices, userId);
+                                    userState.mTouchExplorationGrantedServices, userId);
+                            // We will update when the automation service dies.
+                            if (userState.mUiAutomationService == null) {
+                                onUserStateChangedLocked(userState);
+                            }
                             return;
                         }
                     }
@@ -270,8 +278,8 @@
                     if (userId != mCurrentUserId) {
                         return false;
                     }
-                    UserState state = getUserStateLocked(userId);
-                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
+                    UserState userState = getUserStateLocked(userId);
+                    Iterator<ComponentName> it = userState.mEnabledServices.iterator();
                     while (it.hasNext()) {
                         ComponentName comp = it.next();
                         String compPkg = comp.getPackageName();
@@ -283,7 +291,11 @@
                                 it.remove();
                                 persistComponentNamesToSettingLocked(
                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                                        state.mEnabledServices, userId);
+                                        userState.mEnabledServices, userId);
+                                // We will update when the automation service dies.
+                                if (userState.mUiAutomationService == null) {
+                                    onUserStateChangedLocked(userState);
+                                }
                             }
                         }
                     }
@@ -310,7 +322,13 @@
                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                    restoreStateFromMementoIfNeeded();
+                    // We will update when the automation service dies.
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readConfigurationForUserStateLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
+                    }
                 }
             }
         }, UserHandle.ALL, intentFilter, null, null);
@@ -329,7 +347,7 @@
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
                 }
-                return getClientState(userState);
+                return userState.getClientState();
             } else {
                 userState.mClients.register(client);
                 // If this client is not for the current user we do not
@@ -339,7 +357,7 @@
                     Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
                             + " and userId:" + mCurrentUserId);
                 }
-                return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
+                return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
             }
         }
     }
@@ -385,7 +403,7 @@
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             result = mEnabledServicesForFeedbackTempList;
             result.clear();
-            List<Service> services = getUserStateLocked(resolvedUserId).mServices;
+            List<Service> services = getUserStateLocked(resolvedUserId).mBoundServices;
             while (feedbackType != 0) {
                 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
                 feedbackType &= ~feedbackTypeBit;
@@ -410,7 +428,7 @@
             if (resolvedUserId != mCurrentUserId) {
                 return;
             }
-            services = getUserStateLocked(resolvedUserId).mServices;
+            services = getUserStateLocked(resolvedUserId).mBoundServices;
         }
         for (int i = 0, count = services.size(); i < count; i++) {
             Service service = services.get(i);
@@ -514,36 +532,48 @@
             AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
-        ComponentName componentName = new ComponentName("foo.bar",
-                "AutomationAccessibilityService");
+
+        accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName);
+
         synchronized (mLock) {
-            if (mUiAutomationService != null) {
+            UserState userState = getCurrentUserStateLocked();
+
+            if (userState.mUiAutomationService != null) {
                 throw new IllegalStateException("UiAutomationService " + serviceClient
                         + "already registered!");
             }
-            // If an automation services is connected to the system all services are stopped
-            // so the automation one is the only one running. Settings are not changed so when
-            // the automation service goes away the state is restored from the settings.
-            UserState userState = getCurrentUserStateLocked();
-            unbindAllServicesLocked(userState);
 
-            // If necessary enable accessibility and announce that.
-            if (!userState.mIsAccessibilityEnabled) {
-                userState.mIsAccessibilityEnabled = true;
-            }
-            // No touch exploration.
+            userState.mUiAutomationServiceClient = serviceClient;
+
+            // Set the temporary state.
+            userState.mIsAccessibilityEnabled = true;
             userState.mIsTouchExplorationEnabled = false;
-
-            // No touch enhanced web accessibility.
             userState.mIsEnhancedWebAccessibilityEnabled = false;
+            userState.mIsDisplayMagnificationEnabled = false;
+            userState.mInstalledServices.add(accessibilityServiceInfo);
+            userState.mEnabledServices.clear();
+            userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
+            userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
 
-            // Hook the automation service up.
-            mUiAutomationService = new Service(mCurrentUserId, componentName,
-                    accessibilityServiceInfo, true);
-            mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
+            // Use the new state instead of settings.
+            onUserStateChangedLocked(userState);
+        }
+    }
 
-            scheduleUpdateInputFilter(userState);
-            scheduleSendStateToClientsLocked(userState);
+    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
+        synchronized (mLock) {
+            UserState userState = getCurrentUserStateLocked();
+            // Automation service is not bound, so pretend it died to perform clean up.
+            if (userState.mUiAutomationService != null
+                    && userState.mUiAutomationService.mServiceInterface != null
+                    && serviceClient != null
+                    && userState.mUiAutomationService.mServiceInterface.asBinder()
+                    == serviceClient.asBinder()) {
+                userState.mUiAutomationService.binderDied();
+            } else {
+                throw new IllegalStateException("UiAutomationService " + serviceClient
+                        + " not registered!");
+            }
         }
     }
 
@@ -560,36 +590,26 @@
             return;
         }
         synchronized (mLock) {
-            UserState userState = getCurrentUserStateLocked();
-            // Stash the old state so we can restore it when the keyguard is gone.
-            mTempStateChangeForCurrentUserMemento.initialize(getCurrentUserStateLocked());
             // Set the temporary state.
+            UserState userState = getCurrentUserStateLocked();
+
+            // This is a nop if UI automation is enabled.
+            if (userState.mUiAutomationService != null) {
+                return;
+            }
+
             userState.mIsAccessibilityEnabled = true;
             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
             userState.mIsEnhancedWebAccessibilityEnabled = false;
             userState.mIsDisplayMagnificationEnabled = false;
             userState.mEnabledServices.clear();
             userState.mEnabledServices.add(service);
+            userState.mBindingServices.clear();
             userState.mTouchExplorationGrantedServices.clear();
             userState.mTouchExplorationGrantedServices.add(service);
-            // Update the internal state.
-            performServiceManagementLocked(userState);
-            scheduleUpdateInputFilter(userState);
-            scheduleSendStateToClientsLocked(userState);
-        }
-    }
 
-    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
-        synchronized (mLock) {
-            // Automation service is not bound, so pretend it died to perform clean up.
-            if (mUiAutomationService != null && mUiAutomationService.mServiceInterface != null
-                    && serviceClient != null && mUiAutomationService.mServiceInterface
-                            .asBinder() == serviceClient.asBinder()) {
-                mUiAutomationService.binderDied();
-            } else {
-                throw new IllegalStateException("UiAutomationService " + serviceClient
-                        + " not registered!");
-            }
+            // User the current state instead settings.
+            onUserStateChangedLocked(userState);
         }
     }
 
@@ -695,10 +715,6 @@
 
     private void switchUser(int userId) {
         synchronized (mLock) {
-            // The user switched so we do not need to restore the current user
-            // state since we will fully rebuild it when he becomes current again.
-            mTempStateChangeForCurrentUserMemento.clear();
-
             // Disconnect from services for the old user.
             UserState oldUserState = getUserStateLocked(mCurrentUserId);
             unbindAllServicesLocked(oldUserState);
@@ -716,9 +732,14 @@
             // The user changed.
             mCurrentUserId = userId;
 
-            // Recreate the internal state for the new user.
-            mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
-                    mCurrentUserId, 0).sendToTarget();
+            UserState userState = getCurrentUserStateLocked();
+            if (userState.mUiAutomationService != null) {
+                // Switching users disables the UI automation service.
+                userState.mUiAutomationService.binderDied();
+            } else if (readConfigurationForUserStateLocked(userState)) {
+                // Update the user state if needed.
+               onUserStateChangedLocked(userState);
+            }
 
             if (announceNewUser) {
                 // Schedule announcement of the current user if needed.
@@ -734,25 +755,11 @@
         }
     }
 
-    private void restoreStateFromMementoIfNeeded() {
-        synchronized (mLock) {
-            if (mTempStateChangeForCurrentUserMemento.mUserId != UserHandle.USER_NULL) {
-                UserState userState = getCurrentUserStateLocked();
-                // Restore the state from the memento.
-                mTempStateChangeForCurrentUserMemento.applyTo(userState);
-                mTempStateChangeForCurrentUserMemento.clear();
-                // Update the internal state.
-                performServiceManagementLocked(userState);
-                scheduleUpdateInputFilter(userState);
-                scheduleSendStateToClientsLocked(userState);
-            }
-        }
-    }
-
     private Service getQueryBridge() {
         if (mQueryBridge == null) {
             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-            mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
+            mQueryBridge = new Service(UserHandle.USER_NULL,
+                    sFakeAccessibilityServiceComponentName, info);
         }
         return mQueryBridge;
     }
@@ -768,8 +775,8 @@
         //       behavior is observed from different combinations of
         //       enabled accessibility services.
         UserState state = getCurrentUserStateLocked();
-        for (int i = state.mServices.size() - 1; i >= 0; i--) {
-            Service service = state.mServices.get(i);
+        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+            Service service = state.mBoundServices.get(i);
             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
                 service.notifyGesture(gestureId);
                 return true;
@@ -780,8 +787,8 @@
 
     private void notifyClearAccessibilityNodeInfoCacheLocked() {
         UserState state = getCurrentUserStateLocked();
-        for (int i = state.mServices.size() - 1; i >= 0; i--) {
-            Service service = state.mServices.get(i);
+        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+            Service service = state.mBoundServices.get(i);
             service.notifyClearAccessibilityNodeInfoCache();
         }
     }
@@ -807,8 +814,8 @@
         }
     }
 
-    private void populateInstalledAccessibilityServiceLocked(UserState userState) {
-        userState.mInstalledServices.clear();
+    private boolean readInstalledAccessibilityServiceLocked(UserState userState) {
+        mTempAccessibilityServiceInfoList.clear();
 
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
@@ -829,26 +836,53 @@
             AccessibilityServiceInfo accessibilityServiceInfo;
             try {
                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
-                userState.mInstalledServices.add(accessibilityServiceInfo);
+                mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
             } catch (XmlPullParserException xppe) {
                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
             } catch (IOException ioe) {
                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
             }
         }
+
+        if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) {
+            userState.mInstalledServices.clear();
+            userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList);
+            mTempAccessibilityServiceInfoList.clear();
+            return true;
+        }
+
+        mTempAccessibilityServiceInfoList.clear();
+        return false;
     }
 
-    private void populateEnabledAccessibilityServicesLocked(UserState userState) {
-        populateComponentNamesFromSettingLocked(
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                userState.mUserId,
-                userState.mEnabledServices);
+    private boolean readEnabledAccessibilityServicesLocked(UserState userState) {
+        mTempComponentNameSet.clear();
+        readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userState.mUserId, mTempComponentNameSet);
+        if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
+            userState.mEnabledServices.clear();
+            userState.mEnabledServices.addAll(mTempComponentNameSet);
+            mTempComponentNameSet.clear();
+            return true;
+        }
+        mTempComponentNameSet.clear();
+        return false;
     }
 
-    private void populateTouchExplorationGrantedAccessibilityServicesLocked(UserState userState) {
-        populateComponentNamesFromSettingLocked(
+    private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
+            UserState userState) {
+        mTempComponentNameSet.clear();
+        readComponentNamesFromSettingLocked(
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                userState.mUserId, userState.mTouchExplorationGrantedServices);
+                userState.mUserId, mTempComponentNameSet);
+        if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
+            userState.mTouchExplorationGrantedServices.clear();
+            userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
+            mTempComponentNameSet.clear();
+            return true;
+        }
+        mTempComponentNameSet.clear();
+        return false;
     }
 
     /**
@@ -862,8 +896,8 @@
             boolean isDefault) {
         try {
             UserState state = getCurrentUserStateLocked();
-            for (int i = 0, count = state.mServices.size(); i < count; i++) {
-                Service service = state.mServices.get(i);
+            for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
+                Service service = state.mBoundServices.get(i);
 
                 if (service.mIsDefault == isDefault) {
                     if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
@@ -880,25 +914,12 @@
         }
     }
 
-    /**
-     * Adds a service for a user.
-     *
-     * @param service The service to add.
-     * @param userId The user id.
-     */
-    private void tryAddServiceLocked(Service service, int userId) {
+    private void addServiceLocked(Service service, UserState userState) {
         try {
-            UserState userState = getUserStateLocked(userId);
-            if (userState.mServices.contains(service)) {
-                return;
-            }
             service.linkToOwnDeath();
-            userState.mServices.add(service);
+            userState.mBoundServices.add(service);
             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
-            scheduleUpdateInputFilter(userState);
-            tryEnableTouchExplorationLocked(service);
-            tryEnableEnhancedWebAccessibilityLocked(service);
-        } catch (RemoteException e) {
+        } catch (RemoteException re) {
             /* do nothing */
         }
     }
@@ -909,19 +930,12 @@
      * @param service The service.
      * @return True if the service was removed, false otherwise.
      */
-    private boolean tryRemoveServiceLocked(Service service) {
+    private void removeServiceLocked(Service service) {
         UserState userState = getUserStateLocked(service.mUserId);
-        final boolean removed = userState.mServices.remove(service);
-        if (!removed) {
-            return false;
-        }
+        userState.mBoundServices.remove(service);
         userState.mComponentNameToServiceMap.remove(service.mComponentName);
         service.unlinkToOwnDeath();
         service.dispose();
-        scheduleUpdateInputFilter(userState);
-        tryDisableTouchExplorationLocked(service);
-        tryDisableEnhancedWebAccessibilityLocked(service);
-        return removed;
     }
 
     /**
@@ -969,29 +983,11 @@
         return false;
     }
 
-    /**
-     * Manages services by starting enabled ones and stopping disabled ones.
-     */
-    private void manageServicesLocked(UserState userState) {
-        final int enabledInstalledServicesCount = updateServicesStateLocked(userState);
-        // No enabled installed services => disable accessibility to avoid
-        // sending accessibility events with no recipient across processes.
-        if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
-        }
-    }
-
-    /**
-     * Unbinds all bound services for a user.
-     *
-     * @param userState The user state.
-     */
     private void unbindAllServicesLocked(UserState userState) {
-        List<Service> services = userState.mServices;
+        List<Service> services = userState.mBoundServices;
         for (int i = 0, count = services.size(); i < count; i++) {
             Service service = services.get(i);
-            if (service.unbind()) {
+            if (service.unbindLocked()) {
                 i--;
                 count--;
             }
@@ -1006,7 +1002,7 @@
      * @param userId The user id.
      * @param outComponentNames The output component names.
      */
-    private void populateComponentNamesFromSettingLocked(String settingName, int userId,
+    private void readComponentNamesFromSettingLocked(String settingName, int userId,
             Set<ComponentName> outComponentNames) {
         String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 settingName, userId);
@@ -1047,19 +1043,11 @@
                 settingName, builder.toString(), userId);
     }
 
-    /**
-     * Updates the state of each service by starting (or keeping running) enabled ones and
-     * stopping the rest.
-     *
-     * @param userState The user state for which to do that.
-     * @return The number of enabled installed services.
-     */
-    private int updateServicesStateLocked(UserState userState) {
+    private void manageServicesLocked(UserState userState) {
         Map<ComponentName, Service> componentNameToServiceMap =
                 userState.mComponentNameToServiceMap;
         boolean isEnabled = userState.mIsAccessibilityEnabled;
 
-        int enabledInstalledServices = 0;
         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
             ComponentName componentName = ComponentName.unflattenFromString(
@@ -1067,32 +1055,46 @@
             Service service = componentNameToServiceMap.get(componentName);
 
             if (isEnabled) {
+                // Wait for the binding if it is in process.
+                if (userState.mBindingServices.contains(componentName)) {
+                    continue;
+                }
+                // No enabled installed services => disable accessibility to avoid
+                // sending accessibility events with no recipient across processes.
+                if (userState.mEnabledServices.isEmpty()) {
+                    userState.mIsAccessibilityEnabled = false;
+                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
+                    return;
+                }
                 if (userState.mEnabledServices.contains(componentName)) {
                     if (service == null) {
-                        service = new Service(userState.mUserId, componentName,
-                                installedService, false);
+                        service = new Service(userState.mUserId, componentName, installedService);
+                    } else if (userState.mBoundServices.contains(service)) {
+                        continue;
                     }
-                    service.bind();
-                    enabledInstalledServices++;
+                    service.bindLocked();
                 } else {
                     if (service != null) {
-                        service.unbind();
+                        service.unbindLocked();
                     }
                 }
             } else {
                 if (service != null) {
-                    service.unbind();
+                    service.unbindLocked();
+                } else {
+                    userState.mBindingServices.remove(componentName);
                 }
             }
         }
-
-        return enabledInstalledServices;
     }
 
-    private void scheduleSendStateToClientsLocked(UserState userState) {
-        if (mGlobalClients.getRegisteredCallbackCount() > 0
-                || userState.mClients.getRegisteredCallbackCount() > 0) {
-            final int clientState = getClientState(userState);
+    private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
+        final int clientState = userState.getClientState();
+        if (userState.mLastSentClientState != clientState
+                && (mGlobalClients.getRegisteredCallbackCount() > 0
+                        || userState.mClients.getRegisteredCallbackCount() > 0)) {
+            userState.mLastSentClientState = clientState;
             mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
                     clientState, userState.mUserId) .sendToTarget();
         }
@@ -1144,10 +1146,10 @@
     }
 
     private void showEnableTouchExplorationDialog(final Service service) {
-        String label = service.mResolveInfo.loadLabel(
-
-        mContext.getPackageManager()).toString();
         synchronized (mLock) {
+            String label = service.mResolveInfo.loadLabel(
+            mContext.getPackageManager()).toString();
+
             final UserState state = getCurrentUserStateLocked();
             if (state.mIsTouchExplorationEnabled) {
                 return;
@@ -1167,9 +1169,12 @@
                                  Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                                  state.mTouchExplorationGrantedServices, state.mUserId);
                          // Enable touch exploration.
+                         UserState userState = getUserStateLocked(service.mUserId);
+                         userState.mIsTouchExplorationEnabled = true;
                          Settings.Secure.putIntForUser(mContext.getContentResolver(),
                                  Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
                                  service.mUserId);
+                         onUserStateChangedLocked(userState);
                      }
                  })
                  .setNegativeButton(android.R.string.cancel, new OnClickListener() {
@@ -1191,92 +1196,104 @@
         }
     }
 
-    private int getClientState(UserState userState) {
-        int clientState = 0;
-        if (userState.mIsAccessibilityEnabled) {
-            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
-        }
-        // Touch exploration relies on enabled accessibility.
-        if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
-            clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
-        }
-        return clientState;
-    }
-
-    private void recreateInternalStateLocked(UserState userState) {
-        populateInstalledAccessibilityServiceLocked(userState);
-        populateEnabledAccessibilityServicesLocked(userState);
-        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
-        populatedEnhancedWebAccessibilityEnabledChangedLocked(userState);
-
-        handleTouchExplorationEnabledSettingChangedLocked(userState);
-        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
-        handleAccessibilityEnabledSettingChangedLocked(userState);
-        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
-
-        performServiceManagementLocked(userState);
-
+    private void onUserStateChangedLocked(UserState userState) {
+        updateServicesLocked(userState);
+        updateTouchExplorationLocked(userState);
+        updateEnhancedWebAccessibilityLocked(userState);
         scheduleUpdateInputFilter(userState);
-        scheduleSendStateToClientsLocked(userState);
+        scheduleUpdateClientsIfNeededLocked(userState);
     }
 
-    private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
-        userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
-               mContext.getContentResolver(),
-               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
-    }
-
-    private void performServiceManagementLocked(UserState userState) {
-        if (userState.mIsAccessibilityEnabled ) {
+    private void updateServicesLocked(UserState userState) {
+        if (userState.mIsAccessibilityEnabled) {
             manageServicesLocked(userState);
         } else {
             unbindAllServicesLocked(userState);
         }
     }
 
-    private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
-        userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
+    private boolean readConfigurationForUserStateLocked(UserState userState) {
+        boolean somthingChanged = false;
+        somthingChanged |= readAccessibilityEnabledSettingLocked(userState);
+        somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
+        somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
+        somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
+        somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
+        somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
+        somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+        return somthingChanged;
     }
 
-    private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
-        userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
+    private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
+        final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
+               mContext.getContentResolver(),
+               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
+        if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
+            userState.mIsAccessibilityEnabled = accessibilityEnabled;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
+        final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
+        if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) {
+            userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) {
+        final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
                 0, userState.mUserId) == 1;
+        if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) {
+            userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled;
+            return true;
+        }
+        return false;
     }
 
-    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
-            UserState userState) {
-        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
-        final int serviceCount = userState.mServices.size();
+    private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
+         final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+                0, userState.mUserId) == 1;
+         if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) {
+             userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled;
+             return true;
+         }
+         return false;
+    }
+
+    private void updateTouchExplorationLocked(UserState userState) {
+        userState.mIsTouchExplorationEnabled = false;
+        final int serviceCount = userState.mBoundServices.size();
         for (int i = 0; i < serviceCount; i++) {
-            Service service = userState.mServices.get(i);
-            tryEnableTouchExplorationLocked(service);
+            Service service = userState.mBoundServices.get(i);
+            if (tryEnableTouchExplorationLocked(service)) {
+                break;
+            }
         }
     }
 
-    private void populatedEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
-        userState.mIsEnhancedWebAccessibilityEnabled = Settings.Secure.getIntForUser(
-                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
-                0, userState.mUserId) == 1;
-    }
-
-    private void tryEnableTouchExplorationLocked(Service service) {
+    private boolean tryEnableTouchExplorationLocked(Service service) {
         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
-            return;
+            return false;
         }
         UserState userState = getUserStateLocked(service.mUserId);
         if (userState.mIsTouchExplorationEnabled) {
-            return;
+            return false;
         }
         // UI test automation service can always enable it.
         if (service.mIsAutomation) {
+            userState.mIsTouchExplorationEnabled = true;
             Settings.Secure.putIntForUser(mContext.getContentResolver(),
                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
-            return;
+            return true;
         }
         if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
                 <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@@ -1287,11 +1304,15 @@
                 if (mEnableTouchExplorationDialog == null
                         || (mEnableTouchExplorationDialog != null
                             && !mEnableTouchExplorationDialog.isShowing())) {
-                    showEnableTouchExplorationDialog(service);
+                    mMainHandler.obtainMessage(
+                            MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG,
+                            service).sendToTarget();
                 }
             } else {
+                userState.mIsTouchExplorationEnabled = true;
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
+                return true;
             }
         } else {
             // Starting in JB-MR2 we request a permission to allow a service to enable
@@ -1299,94 +1320,43 @@
             if (mContext.getPackageManager().checkPermission(
                     android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
                     service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+                userState.mIsTouchExplorationEnabled = true;
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
+                return true;
             }
         }
+        return false;
     }
 
-    private void tryDisableTouchExplorationLocked(Service service) {
-        if (!service.mRequestTouchExplorationMode) {
-            return;
-        }
-        UserState userState = getUserStateLocked(service.mUserId);
-        if (!userState.mIsTouchExplorationEnabled) {
-            return;
-        }
-        final int serviceCount = userState.mServices.size();
+    private void updateEnhancedWebAccessibilityLocked(UserState userState) {
+        userState.mIsEnhancedWebAccessibilityEnabled = false;
+        final int serviceCount = userState.mBoundServices.size();
         for (int i = 0; i < serviceCount; i++) {
-            Service other = userState.mServices.get(i);
-            if (other != service) {
-                if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
-                        <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                    // Up to JB-MR1 we had a white list with services that can enable touch
-                    // exploration. When a service is first started we show a dialog to the
-                    // use to get a permission to white list the service.
-                    if (other.mRequestTouchExplorationMode &&
-                            userState.mTouchExplorationGrantedServices.contains(
-                                    service.mComponentName)) {
-                        // A white-listed service wants touch exploration, do not disable.
-                        return;
-                    }
-                } else {
-                    // Starting in JB-MR2 we request a permission to allow a service to enable
-                    // touch exploration and do not care if the service is in the white list.
-                    if (other.mRequestTouchExplorationMode && (service.mIsAutomation
-                            || mContext.getPackageManager().checkPermission(
-                                    android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
-                                    service.mComponentName.getPackageName())
-                                    == PackageManager.PERMISSION_GRANTED)) {
-                        // A service with permission wants touch exploration, do not disable.
-                        return;
-                    }
-                }
-            }
-        }
-        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
-    }
-
-    private void tryEnableEnhancedWebAccessibilityLocked(Service service) {
-        if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
-            return;
-        }
-        UserState userState = getUserStateLocked(service.mUserId);
-        if (userState.mIsEnhancedWebAccessibilityEnabled) {
-            return;
-        }
-        // Requested and can enabled, do it.
-        if (service.mRequestEnhancedWebAccessibility
-                && canEnabledEnhancedWebAccessibility(service)) {
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
-        }
-    }
-
-    private void tryDisableEnhancedWebAccessibilityLocked(Service service) {
-        if (!service.mRequestEnhancedWebAccessibility) {
-            return;
-        }
-        UserState userState = getUserStateLocked(service.mUserId);
-        if (!userState.mIsEnhancedWebAccessibilityEnabled) {
-            return;
-        }
-        final int serviceCount = userState.mServices.size();
-        for (int i = 0; i < serviceCount; i++) {
-            Service other = userState.mServices.get(i);
-            if (other != service && other.mRequestEnhancedWebAccessibility
-                    && canEnabledEnhancedWebAccessibility(other)) {
-                // One service requests the feature, do not disable.
+            Service service = userState.mBoundServices.get(i);
+            if (tryEnableEnhancedWebAccessibilityLocked(service)) {
                 return;
             }
         }
-        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0, service.mUserId);
     }
 
-    private boolean canEnabledEnhancedWebAccessibility(Service service) {
-        return (service.mIsAutomation || mContext.getPackageManager().checkPermission(
+    private boolean tryEnableEnhancedWebAccessibilityLocked(Service service) {
+        if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
+            return false;
+        }
+        UserState userState = getUserStateLocked(service.mUserId);
+        if (userState.mIsEnhancedWebAccessibilityEnabled) {
+            return false;
+        }
+        if (service.mIsAutomation || mContext.getPackageManager().checkPermission(
                 android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
-                service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED);
+                service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+            userState.mIsEnhancedWebAccessibilityEnabled = true;
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -1395,12 +1365,6 @@
         synchronized (mLock) {
             pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
             pw.println();
-            pw.println("Ui automation service: bound=" + (mUiAutomationService != null));
-            pw.println();
-            if (mUiAutomationService != null) {
-                mUiAutomationService.dump(fd, pw, args);
-                pw.println();
-            }
             final int userCount = mUserStates.size();
             for (int i = 0; i < userCount; i++) {
                 UserState userState = mUserStates.valueAt(i);
@@ -1410,17 +1374,22 @@
                 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
                 pw.append(", displayMagnificationEnabled="
                         + userState.mIsDisplayMagnificationEnabled);
+                if (userState.mUiAutomationService != null) {
+                    pw.append(", ");
+                    userState.mUiAutomationService.dump(fd, pw, args);
+                    pw.println();
+                }
                 pw.append("}");
                 pw.println();
                 pw.append("           services:{");
-                final int serviceCount = userState.mServices.size();
+                final int serviceCount = userState.mBoundServices.size();
                 for (int j = 0; j < serviceCount; j++) {
                     if (j > 0) {
                         pw.append(", ");
                         pw.println();
                         pw.append("                     ");
                     }
-                    Service service = userState.mServices.get(j);
+                    Service service = userState.mBoundServices.get(j);
                     service.dump(fd, pw, args);
                 }
                 pw.println("}]");
@@ -1462,10 +1431,10 @@
         public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
         public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
         public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
-        public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4;
-        public static final int MSG_UPDATE_ACTIVE_WINDOW = 5;
-        public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 6;
-        public static final int MSG_UPDATE_INPUT_FILTER = 7;
+        public static final int MSG_UPDATE_ACTIVE_WINDOW = 4;
+        public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
+        public static final int MSG_UPDATE_INPUT_FILTER = 6;
+        public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -1494,13 +1463,6 @@
                     final int userId = msg.arg1;
                     sendStateToClientsForUser(0, userId);
                 } break;
-                case MSG_SEND_RECREATE_INTERNAL_STATE: {
-                    final int userId = msg.arg1;
-                    synchronized (mLock) {
-                        UserState userState = getUserStateLocked(userId);
-                        recreateInternalStateLocked(userState);
-                    }
-                } break;
                 case MSG_UPDATE_ACTIVE_WINDOW: {
                     final int windowId = msg.arg1;
                     final int eventType = msg.arg2;
@@ -1513,6 +1475,10 @@
                     UserState userState = (UserState) msg.obj;
                     updateInputFilter(userState);
                 } break;
+                case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: {
+                    Service service = (Service) msg.obj;
+                    showEnableTouchExplorationDialog(service);
+                } break;
             }
         }
 
@@ -1641,14 +1607,14 @@
         };
 
         public Service(int userId, ComponentName componentName,
-                AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
+                AccessibilityServiceInfo accessibilityServiceInfo) {
             mUserId = userId;
             mResolveInfo = accessibilityServiceInfo.getResolveInfo();
             mId = sIdCounter++;
             mComponentName = componentName;
             mAccessibilityServiceInfo = accessibilityServiceInfo;
-            mIsAutomation = isAutomation;
-            if (!isAutomation) {
+            mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
+            if (!mIsAutomation) {
                 mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
                 mIntent = new Intent().setComponent(mComponentName);
                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
@@ -1688,24 +1654,6 @@
                 mRequestEnhancedWebAccessibility = (info.flags
                            & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
             }
-
-            // If this service is up and running we may have to enable touch
-            // exploration or enhanced web accessibility, otherwise this will
-            // happen when the service connects.
-            synchronized (mLock) {
-                if (canReceiveEventsLocked()) {
-                    if (mRequestTouchExplorationMode) {
-                        tryEnableTouchExplorationLocked(this);
-                    } else {
-                        tryDisableTouchExplorationLocked(this);
-                    }
-                    if (mRequestEnhancedWebAccessibility) {
-                        tryEnableEnhancedWebAccessibilityLocked(this);
-                    } else {
-                        tryDisableEnhancedWebAccessibilityLocked(this);
-                    }
-                }
-            }
         }
 
         /**
@@ -1713,10 +1661,20 @@
          *
          * @return True if binding is successful.
          */
-        public boolean bind() {
-            if (!mIsAutomation && mService == null) {
-                return mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE,
-                        new UserHandle(mUserId));
+        public boolean bindLocked() {
+            UserState userState = getUserStateLocked(mUserId);
+            if (!mIsAutomation) {
+                if (mService == null) {
+                    if (mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE,
+                            new UserHandle(mUserId))) {
+                        userState.mBindingServices.add(mComponentName);
+                    }
+                }
+            } else {
+                userState.mBindingServices.add(mComponentName);
+                mService = userState.mUiAutomationServiceClient.asBinder();
+                onServiceConnected(mComponentName, mService);
+                userState.mUiAutomationService = this;
             }
             return false;
         }
@@ -1727,17 +1685,19 @@
          *
          * @return True if unbinding is successful.
          */
-        public boolean unbind() {
-            if (mService != null) {
-                synchronized (mLock) {
-                    tryRemoveServiceLocked(this);
-                }
-                if (!mIsAutomation) {
-                    mContext.unbindService(this);
-                }
-                return true;
+        public boolean unbindLocked() {
+            if (mService == null) {
+                return false;
             }
-            return false;
+            if (!mIsAutomation) {
+                mContext.unbindService(this);
+            } else {
+                UserState userState = getUserStateLocked(mUserId);
+                userState.mUiAutomationService = null;
+                userState.mUiAutomationServiceClient = null;
+            }
+            removeServiceLocked(this);
+            return true;
         }
 
         public boolean canReceiveEventsLocked() {
@@ -1766,6 +1726,8 @@
                     } else {
                         setDynamicallyConfigurableProperties(info);
                     }
+                    UserState userState = getUserStateLocked(mUserId);
+                    onUserStateChangedLocked(userState);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -1774,15 +1736,24 @@
 
         @Override
         public void onServiceConnected(ComponentName componentName, IBinder service) {
-            mService = service;
-            mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
-            try {
-                mServiceInterface.setConnection(this, mId);
-                synchronized (mLock) {
-                    tryAddServiceLocked(this, mUserId);
+            final int connectionId;
+            synchronized (mLock) {
+                connectionId = mId;
+                mService = service;
+                mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
+                UserState userState = getUserStateLocked(mUserId);
+                if (!userState.mBindingServices.contains(mComponentName)) {
+                    binderDied();
+                } else {
+                    userState.mBindingServices.remove(mComponentName);
+                    addServiceLocked(this, userState);
+                    onUserStateChangedLocked(userState);
                 }
+            }
+            try {
+                mServiceInterface.setConnection(this, connectionId);
             } catch (RemoteException re) {
-                Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
+                Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re);
             }
         }
 
@@ -2128,13 +2099,15 @@
         public void binderDied() {
             synchronized (mLock) {
                 // The death recipient is unregistered in tryRemoveServiceLocked
-                tryRemoveServiceLocked(this);
-                // We no longer have an automation service, so restore
-                // the state based on values in the settings database.
+                removeServiceLocked(this);
+                UserState userState = getUserStateLocked(mUserId);
                 if (mIsAutomation) {
-                    mUiAutomationService = null;
-                    recreateInternalStateLocked(getUserStateLocked(mUserId));
+                    // We no longer have an automation service, so restore
+                    // the state based on values in the settings database.
+                    userState.mUiAutomationService = null;
+                    userState.mUiAutomationServiceClient = null;
                 }
+                onUserStateChangedLocked(userState);
             }
         }
 
@@ -2585,7 +2558,7 @@
     private class UserState {
         public final int mUserId;
 
-        public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
+        public final CopyOnWriteArrayList<Service> mBoundServices = new CopyOnWriteArrayList<Service>();
 
         public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
             new RemoteCallbackList<IAccessibilityManagerClient>();
@@ -2596,6 +2569,8 @@
         public final List<AccessibilityServiceInfo> mInstalledServices =
                 new ArrayList<AccessibilityServiceInfo>();
 
+        public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>();
+
         public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
 
         public final Set<ComponentName> mTouchExplorationGrantedServices =
@@ -2609,57 +2584,30 @@
 
         public int mHandledFeedbackTypes = 0;
 
+        public int mLastSentClientState;
+
         public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
         public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
 
+        private Service mUiAutomationService;
+        private IAccessibilityServiceClient mUiAutomationServiceClient;
+
         public UserState(int userId) {
             mUserId = userId;
         }
-    }
 
-    private class TempUserStateChangeMemento {
-        public int mUserId = UserHandle.USER_NULL;
-        public boolean mIsAccessibilityEnabled;
-        public boolean mIsTouchExplorationEnabled;
-        public boolean mIsEnhancedWebAccessibilityEnabled;
-        public boolean mIsDisplayMagnificationEnabled;
-        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
-        public final Set<ComponentName> mTouchExplorationGrantedServices =
-                new HashSet<ComponentName>();
-
-        public void initialize(UserState userState) {
-            mUserId = userState.mUserId;
-            mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled;
-            mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled;
-            mIsEnhancedWebAccessibilityEnabled = userState.mIsEnhancedWebAccessibilityEnabled;
-            mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled;
-            mEnabledServices.clear();
-            mEnabledServices.addAll(userState.mEnabledServices);
-            mTouchExplorationGrantedServices.clear();
-            mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices);
-        }
-
-        public void applyTo(UserState userState) {
-            userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled;
-            userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled;
-            userState.mIsEnhancedWebAccessibilityEnabled = mIsEnhancedWebAccessibilityEnabled;
-            userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled;
-            userState.mEnabledServices.clear();
-            userState.mEnabledServices.addAll(mEnabledServices);
-            userState.mTouchExplorationGrantedServices.clear();
-            userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices);
-        }
-
-        public void clear() {
-            mUserId = UserHandle.USER_NULL;
-            mIsAccessibilityEnabled = false;
-            mIsTouchExplorationEnabled = false;
-            mIsEnhancedWebAccessibilityEnabled = false;
-            mIsDisplayMagnificationEnabled = false;
-            mEnabledServices.clear();
-            mTouchExplorationGrantedServices.clear();
+        public int getClientState() {
+            int clientState = 0;
+            if (mIsAccessibilityEnabled) {
+                clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+            }
+            // Touch exploration relies on enabled accessibility.
+            if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+                clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+            }
+            return clientState;
         }
     }
 
@@ -2680,7 +2628,7 @@
         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
 
-        private final Uri mAccessibilityScriptInjectionUri = Settings.Secure
+        private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
                 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
 
         public AccessibilityContentObserver(Handler handler) {
@@ -2699,7 +2647,7 @@
             contentResolver.registerContentObserver(
                     mTouchExplorationGrantedAccessibilityServicesUri,
                     false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(mAccessibilityScriptInjectionUri,
+            contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
                     false, this, UserHandle.USER_ALL);
         }
 
@@ -2708,58 +2656,61 @@
             if (mAccessibilityEnabledUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        handleAccessibilityEnabledSettingChangedLocked(userState);
-                        performServiceManagementLocked(userState);
-                        scheduleUpdateInputFilter(userState);
-                        scheduleSendStateToClientsLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readAccessibilityEnabledSettingLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             } else if (mTouchExplorationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        handleTouchExplorationEnabledSettingChangedLocked(userState);
-                        scheduleUpdateInputFilter(userState);
-                        scheduleSendStateToClientsLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readTouchExplorationEnabledSettingLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
-                        scheduleUpdateInputFilter(userState);
-                        scheduleSendStateToClientsLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readDisplayMagnificationEnabledSettingLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        populateEnabledAccessibilityServicesLocked(userState);
-                        manageServicesLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readEnabledAccessibilityServicesLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
-                        handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
-            } else if (mAccessibilityScriptInjectionUri.equals(uri)) {
+            } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
                 synchronized (mLock) {
                     // We will update when the automation service dies.
-                    if (mUiAutomationService == null) {
-                        UserState userState = getCurrentUserStateLocked();
-                        populatedEnhancedWebAccessibilityEnabledChangedLocked(userState);
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
+                            onUserStateChangedLocked(userState);
+                        }
                     }
                 }
             }
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 88603dc..2a62c17 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -21,6 +21,7 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerResponse;
 import android.accounts.AuthenticatorDescription;
 import android.accounts.GrantCredentialsPermissionActivity;
 import android.accounts.IAccountAuthenticator;
@@ -526,6 +527,9 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
+        if (!canUserModifyAccounts(Binder.getCallingUid())) {
+            return false;
+        }
 
         UserAccounts accounts = getUserAccountsForCaller();
         // fails if the account already exists
@@ -679,6 +683,14 @@
         checkManageAccountsPermission();
         UserHandle user = Binder.getCallingUserHandle();
         UserAccounts accounts = getUserAccountsForCaller();
+        if (!canUserModifyAccounts(Binder.getCallingUid())) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "User cannot modify accounts");
+            } catch (RemoteException re) {
+            }
+        }
+
         long identityToken = clearCallingIdentity();
 
         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
@@ -2312,6 +2324,17 @@
                 Manifest.permission.USE_CREDENTIALS);
     }
 
+    private boolean canUserModifyAccounts(int callingUid) {
+        if (callingUid != android.os.Process.myUid()) {
+            Bundle restrictions = getUserManager().getUserRestrictions(
+                    new UserHandle(UserHandle.getUserId(callingUid)));
+            if (!restrictions.getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
             throws RemoteException {
         final int callingUid = getCallingUid();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7b6e79e..22af3d5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -37,6 +37,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -328,7 +329,7 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+    private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
     public class PendingActivityExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
@@ -596,13 +597,8 @@
      * List of PendingThumbnailsRecord objects of clients who are still
      * waiting to receive all of the thumbnails for a task.
      */
-    final ArrayList mPendingThumbnails = new ArrayList();
-
-    /**
-     * List of HistoryRecord objects that have been finished and must
-     * still report back to a pending thumbnail receiver.
-     */
-    final ArrayList mCancelledThumbnails = new ArrayList();
+    final ArrayList<PendingThumbnailsRecord> mPendingThumbnails =
+            new ArrayList<PendingThumbnailsRecord>();
 
     final ProviderMap mProviderMap;
 
@@ -2842,11 +2838,8 @@
             for (int i=0; i<activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing) {
-                    int index = mMainStack.indexOfTokenLocked(r.appToken);
-                    if (index >= 0) {
-                        mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
-                                null, "finish-heavy", true);
-                    }
+                    mMainStack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "finish-heavy", true);
                 }
             }
             
@@ -2932,22 +2925,13 @@
         }
     }
 
+    @Override
     public boolean willActivityBeVisible(IBinder token) {
         synchronized(this) {
-            int i;
-            for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r.appToken == token) {
-                    return true;
-                }
-                if (r.fullscreen && !r.finishing) {
-                    return false;
-                }
-            }
-            return true;
+            return mMainStack.willActivityBeVisibleLocked(token);
         }
     }
-    
+
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) {
         synchronized(this) {
@@ -3717,13 +3701,7 @@
         }
         mWindowManager.closeSystemDialogs(reason);
 
-        for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                r.stack.finishActivityLocked(r, i,
-                        Activity.RESULT_CANCELED, null, "close-sys", true);
-            }
-        }
+        mMainStack.closeSystemDialogsLocked();
 
         broadcastIntentLocked(null, null, intent, null,
                 null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
@@ -3930,37 +3908,12 @@
         boolean didSomething = killPackageProcessesLocked(name, appId, userId,
                 -100, callerWillRestart, true, doit, evenPersistent,
                 name == null ? ("force stop user " + userId) : ("force stop " + name));
-        
-        TaskRecord lastTask = null;
-        for (i=0; i<mMainStack.mHistory.size(); i++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            final boolean samePackage = r.packageName.equals(name)
-                    || (name == null && r.userId == userId);
-            if ((userId == UserHandle.USER_ALL || r.userId == userId)
-                    && (samePackage || r.task == lastTask)
-                    && (r.app == null || evenPersistent || !r.app.persistent)) {
-                if (!doit) {
-                    if (r.finishing) {
-                        // If this activity is just finishing, then it is not
-                        // interesting as far as something to stop.
-                        continue;
-                    }
-                    return true;
-                }
-                didSomething = true;
-                Slog.i(TAG, "  Force finishing activity " + r);
-                if (samePackage) {
-                    if (r.app != null) {
-                        r.app.removed = true;
-                    }
-                    r.app = null;
-                }
-                lastTask = r.task;
-                if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                        null, "force-stop", true)) {
-                    i--;
-                }
+
+        if (mMainStack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+            if (!doit) {
+                return true;
             }
+            didSomething = true;
         }
 
         if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) {
@@ -5670,12 +5623,12 @@
     // TASK MANAGEMENT
     // =========================================================
 
-    public List getTasks(int maxNum, int flags,
+    @Override
+    public List<RunningTaskInfo> getTasks(int maxNum, int flags,
                          IThumbnailReceiver receiver) {
-        ArrayList list = new ArrayList();
+        ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
 
-        PendingThumbnailsRecord pending = null;
-        IApplicationThread topThumbnail = null;
+        PendingThumbnailsRecord pending = new PendingThumbnailsRecord(receiver);
         ActivityRecord topRecord = null;
 
         synchronized(this) {
@@ -5701,88 +5654,19 @@
                 throw new SecurityException(msg);
             }
 
-            int pos = mMainStack.mHistory.size()-1;
-            ActivityRecord next =
-                pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
-            ActivityRecord top = null;
-            TaskRecord curTask = null;
-            int numActivities = 0;
-            int numRunning = 0;
-            while (pos >= 0 && maxNum > 0) {
-                final ActivityRecord r = next;
-                pos--;
-                next = pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
+            topRecord = mMainStack.getTasksLocked(maxNum, receiver, pending, list);
 
-                // Initialize state for next task if needed.
-                if (top == null ||
-                        (top.state == ActivityState.INITIALIZING
-                            && top.task == r.task)) {
-                    top = r;
-                    curTask = r.task;
-                    numActivities = numRunning = 0;
-                }
-
-                // Add 'r' into the current task.
-                numActivities++;
-                if (r.app != null && r.app.thread != null) {
-                    numRunning++;
-                }
-
-                if (localLOGV) Slog.v(
-                    TAG, r.intent.getComponent().flattenToShortString()
-                    + ": task=" + r.task);
-
-                // If the next one is a different task, generate a new
-                // TaskInfo entry for what we have.
-                if (next == null || next.task != curTask) {
-                    ActivityManager.RunningTaskInfo ci
-                            = new ActivityManager.RunningTaskInfo();
-                    ci.id = curTask.taskId;
-                    ci.baseActivity = r.intent.getComponent();
-                    ci.topActivity = top.intent.getComponent();
-                    if (top.thumbHolder != null) {
-                        ci.description = top.thumbHolder.lastDescription;
-                    }
-                    ci.numActivities = numActivities;
-                    ci.numRunning = numRunning;
-                    //System.out.println(
-                    //    "#" + maxNum + ": " + " descr=" + ci.description);
-                    if (ci.thumbnail == null && receiver != null) {
-                        if (localLOGV) Slog.v(
-                            TAG, "State=" + top.state + "Idle=" + top.idle
-                            + " app=" + top.app
-                            + " thr=" + (top.app != null ? top.app.thread : null));
-                        if (top.state == ActivityState.RESUMED
-                                || top.state == ActivityState.PAUSING) {
-                            if (top.idle && top.app != null
-                                && top.app.thread != null) {
-                                topRecord = top;
-                                topThumbnail = top.app.thread;
-                            } else {
-                                top.thumbnailNeeded = true;
-                            }
-                        }
-                        if (pending == null) {
-                            pending = new PendingThumbnailsRecord(receiver);
-                        }
-                        pending.pendingRecords.add(top);
-                    }
-                    list.add(ci);
-                    maxNum--;
-                    top = null;
-                }
-            }
-
-            if (pending != null) {
+            if (!pending.pendingRecords.isEmpty()) {
                 mPendingThumbnails.add(pending);
             }
         }
 
         if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
 
-        if (topThumbnail != null) {
+        if (topRecord != null) {
             if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
             try {
+                IApplicationThread topThumbnail = topRecord.app.thread;
                 topThumbnail.requestThumbnail(topRecord.appToken);
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
@@ -6017,43 +5901,6 @@
         return false;
     }
     
-    private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
-        int j;
-        TaskRecord startTask = ((ActivityRecord)mMainStack.mHistory.get(startIndex)).task; 
-        TaskRecord jt = startTask;
-        
-        // First look backwards
-        for (j=startIndex-1; j>=0; j--) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
-            if (r.task != jt) {
-                jt = r.task;
-                if (affinity.equals(jt.affinity)) {
-                    return j;
-                }
-            }
-        }
-        
-        // Now look forwards
-        final int N = mMainStack.mHistory.size();
-        jt = startTask;
-        for (j=startIndex+1; j<N; j++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
-            if (r.task != jt) {
-                if (affinity.equals(jt.affinity)) {
-                    return j;
-                }
-                jt = r.task;
-            }
-        }
-        
-        // Might it be at the top?
-        if (affinity.equals(((ActivityRecord)mMainStack.mHistory.get(N-1)).task.affinity)) {
-            return N-1;
-        }
-        
-        return -1;
-    }
-    
     /**
      * TODO: Add mController hook
      */
@@ -6082,20 +5929,8 @@
                     mMainStack.moveTaskToFrontLocked(tr, null, options);
                     return;
                 }
-                for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                    ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
-                    if (hr.task.taskId == task) {
-                        if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
-                            mMainStack.mUserLeaving = true;
-                        }
-                        if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
-                            // Caller wants the home activity moved with it.  To accomplish this,
-                            // we'll just move the home task to the top first.
-                            mMainStack.moveHomeToFrontLocked();
-                        }
-                        mMainStack.moveTaskToFrontLocked(hr.task, null, options);
-                        return;
-                    }
+                if (mMainStack.findTaskToMoveToFrontLocked(task, flags, options)) {
+                    return;
                 }
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -6135,7 +5970,7 @@
         enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            int taskId = getTaskForActivityLocked(token, !nonRoot);
+            int taskId = mMainStack.getTaskForActivityLocked(token, !nonRoot);
             if (taskId >= 0) {
                 return mMainStack.moveTaskToBackLocked(taskId, null);
             }
@@ -6165,27 +6000,10 @@
 
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized(this) {
-            return getTaskForActivityLocked(token, onlyRoot);
+            return mMainStack.getTaskForActivityLocked(token, onlyRoot);
         }
     }
 
-    int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
-        final int N = mMainStack.mHistory.size();
-        TaskRecord lastTask = null;
-        for (int i=0; i<N; i++) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-            if (r.appToken == token) {
-                if (!onlyRoot || lastTask != r.task) {
-                    return r.task.taskId;
-                }
-                return -1;
-            }
-            lastTask = r.task;
-        }
-
-        return -1;
-    }
-
     // =========================================================
     // THUMBNAILS
     // =========================================================
@@ -7091,13 +6909,10 @@
                 "unhandledBack()");
 
         synchronized(this) {
-            int count = mMainStack.mHistory.size();
-            if (DEBUG_SWITCH) Slog.d(
-                TAG, "Performing unhandledBack(): stack size = " + count);
-            if (count > 1) {
-                final long origId = Binder.clearCallingIdentity();
-                mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
-                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                mMainStack.unhandledBackLocked();
+            } finally {
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7925,7 +7740,8 @@
                 }
                 mDidUpdate = true;
             }
-            
+
+            mAppOpsService.systemReady();
             mSystemReady = true;
             if (!mStartRunning) {
                 return;
@@ -8158,15 +7974,7 @@
                     + " has crashed too many times: killing!");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                     app.userId, app.info.processName, app.uid);
-            for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r.app == app) {
-                    Slog.w(TAG, "  Force finishing activity "
-                        + r.intent.getComponent().flattenToShortString());
-                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "crashed", false);
-                }
-            }
+            mMainStack.handleAppCrashLocked(app);
             if (!app.persistent) {
                 // We don't want to start this process again until the user
                 // explicitly does so...  but for persistent process, we really
@@ -8191,33 +7999,7 @@
             }
             mMainStack.resumeTopActivityLocked(null);
         } else {
-            ActivityRecord r = mMainStack.topRunningActivityLocked(null);
-            if (r != null && r.app == app) {
-                // If the top running activity is from this crashing
-                // process, then terminate it to avoid getting in a loop.
-                Slog.w(TAG, "  Force finishing activity "
-                        + r.intent.getComponent().flattenToShortString());
-                int index = mMainStack.indexOfActivityLocked(r);
-                r.stack.finishActivityLocked(r, index,
-                        Activity.RESULT_CANCELED, null, "crashed", false);
-                // Also terminate any activities below it that aren't yet
-                // stopped, to avoid a situation where one will get
-                // re-start our crashing activity once it gets resumed again.
-                index--;
-                if (index >= 0) {
-                    r = (ActivityRecord)mMainStack.mHistory.get(index);
-                    if (r.state == ActivityState.RESUMED
-                            || r.state == ActivityState.PAUSING
-                            || r.state == ActivityState.PAUSED) {
-                        if (!r.isHomeActivity || mHomeProcess != r.app) {
-                            Slog.w(TAG, "  Force finishing activity "
-                                    + r.intent.getComponent().flattenToShortString());
-                            r.stack.finishActivityLocked(r, index,
-                                    Activity.RESULT_CANCELED, null, "crashed", false);
-                        }
-                    }
-                }
-            }
+            mMainStack.finishTopRunningActivityLocked(app);
         }
 
         // Bump up the crash count of any services currently running in the proc.
@@ -9236,8 +9018,7 @@
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
         pw.println("  Main stack:");
-        dumpHistoryList(fd, pw, mMainStack.mHistory, "  ", "Hist", true, !dumpAll, dumpClient,
-                dumpPackage);
+        mMainStack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage);
         pw.println(" ");
         pw.println("  Running activities (most recent first):");
         dumpHistoryList(fd, pw, mMainStack.mLRUActivities, "  ", "Run", false, !dumpAll, false,
@@ -9767,32 +9548,10 @@
      */
     protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
-        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
-
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
-                    activities.add(r1);
-                }
-            }
-        } else if ("top".equals(name)) {
-            synchronized (this) {
-                final int N = mMainStack.mHistory.size();
-                if (N > 0) {
-                    activities.add((ActivityRecord)mMainStack.mHistory.get(N-1));
-                }
-            }
-        } else {
-            ItemMatcher matcher = new ItemMatcher();
-            matcher.build(name);
-
-            synchronized (this) {
-                for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
-                    if (matcher.match(r1, r1.intent.getComponent())) {
-                        activities.add(r1);
-                    }
-                }
-            }
+        ArrayList<ActivityRecord> activities;
+        
+        synchronized (this) {
+            activities = mMainStack.getDumpActivitiesLocked(name);
         }
 
         if (activities.size() <= 0) {
@@ -10044,7 +9803,7 @@
         return needSep;
     }
 
-    private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
+    static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
             String prefix, String label, boolean complete, boolean brief, boolean client,
             String dumpPackage) {
         TaskRecord lastTask = null;
@@ -11779,6 +11538,7 @@
                         synchronized (bs) {
                             bs.removeUidStatsLocked(uid);
                         }
+                        mAppOpsService.uidRemoved(uid);
                     }
                 } else {
                     // If resources are unavailable just force stop all
@@ -11804,6 +11564,10 @@
                             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                         new String[] {ssp}, userId);
+                                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                                    mAppOpsService.packageRemoved(
+                                            intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
+                                }
                             }
                         }
                     }
@@ -12577,95 +12341,14 @@
 
     public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
             Intent resultData) {
-        ComponentName dest = destIntent.getComponent();
 
         synchronized (this) {
             ActivityRecord srec = ActivityRecord.forToken(token);
             if (srec == null) {
                 return false;
             }
-            ArrayList<ActivityRecord> history = srec.stack.mHistory;
-            final int start = history.indexOf(srec);
-            if (start < 0) {
-                // Current activity is not in history stack; do nothing.
-                return false;
-            }
-            int finishTo = start - 1;
-            ActivityRecord parent = null;
-            boolean foundParentInTask = false;
-            if (dest != null) {
-                TaskRecord tr = srec.task;
-                for (int i = start - 1; i >= 0; i--) {
-                    ActivityRecord r = history.get(i);
-                    if (tr != r.task) {
-                        // Couldn't find parent in the same task; stop at the one above this.
-                        // (Root of current task; in-app "home" behavior)
-                        // Always at least finish the current activity.
-                        finishTo = Math.min(start - 1, i + 1);
-                        parent = history.get(finishTo);
-                        break;
-                    } else if (r.info.packageName.equals(dest.getPackageName()) &&
-                            r.info.name.equals(dest.getClassName())) {
-                        finishTo = i;
-                        parent = r;
-                        foundParentInTask = true;
-                        break;
-                    }
-                }
-            }
-
-            if (mController != null) {
-                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
-                if (next != null) {
-                    // ask watcher if this is allowed
-                    boolean resumeOK = true;
-                    try {
-                        resumeOK = mController.activityResuming(next.packageName);
-                    } catch (RemoteException e) {
-                        mController = null;
-                    }
-
-                    if (!resumeOK) {
-                        return false;
-                    }
-                }
-            }
-            final long origId = Binder.clearCallingIdentity();
-            for (int i = start; i > finishTo; i--) {
-                ActivityRecord r = history.get(i);
-                mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                        "navigate-up", true);
-                // Only return the supplied result for the first activity finished
-                resultCode = Activity.RESULT_CANCELED;
-                resultData = null;
-            }
-
-            if (parent != null && foundParentInTask) {
-                final int parentLaunchMode = parent.info.launchMode;
-                final int destIntentFlags = destIntent.getFlags();
-                if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
-                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
-                        (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                    parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
-                } else {
-                    try {
-                        ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                                destIntent.getComponent(), 0, srec.userId);
-                        int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
-                                null, aInfo, parent.appToken, null,
-                                0, -1, parent.launchedFromUid, parent.launchedFromPackage,
-                                0, null, true, null);
-                        foundParentInTask = res == ActivityManager.START_SUCCESS;
-                    } catch (RemoteException e) {
-                        foundParentInTask = false;
-                    }
-                    mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
-                            resultData, "navigate-up", true);
-                }
-            }
-            Binder.restoreCallingIdentity(origId);
-            return foundParentInTask;
+            ActivityStack stack = srec.stack;
+            return stack.navigateUpToLocked(srec, destIntent, resultCode, resultData);
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index ba2e47a..c1b406e 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -22,6 +22,7 @@
 
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -95,9 +96,9 @@
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
     final int requestCode;  // code given by requester (resultTo)
-    ArrayList results;      // pending ActivityResult objs we have received
+    ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
-    ArrayList newIntents;   // any pending new intents for single-top mode
+    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
     ActivityOptions pendingOptions; // most recently given options
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
@@ -574,6 +575,9 @@
      */
     final void deliverNewIntentLocked(int callingUid, Intent intent) {
         boolean sent = false;
+        // The activity now gets access to the data associated with this Intent.
+        service.grantUriPermissionFromIntentLocked(callingUid, packageName,
+                intent, getUriPermissionsLocked());
         // We want to immediately deliver the intent to the activity if
         // it is currently the top resumed activity...  however, if the
         // device is sleeping, then all activities are stopped, so in that
@@ -586,8 +590,6 @@
                 ArrayList<Intent> ar = new ArrayList<Intent>();
                 intent = new Intent(intent);
                 ar.add(intent);
-                service.grantUriPermissionFromIntentLocked(callingUid, packageName,
-                        intent, getUriPermissionsLocked());
                 app.thread.scheduleNewIntent(ar, appToken);
                 sent = true;
             } catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e164d0e..76836f9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -21,19 +21,23 @@
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
-import com.android.server.am.ActivityRecord.Token;
 import com.android.server.wm.AppTransition;
+import com.android.server.wm.TaskGroup;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityController;
 import android.app.IActivityManager;
+import android.app.IThumbnailReceiver;
 import android.app.IThumbnailRetriever;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
 import android.app.ResultInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.IActivityManager.WaitResult;
 import android.content.ComponentName;
 import android.content.Context;
@@ -64,7 +68,9 @@
 import android.util.Slog;
 import android.view.Display;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -151,9 +157,9 @@
     
     /**
      * The back history of all previous (and possibly still
-     * running) activities.  It contains HistoryRecord objects.
+     * running) activities.  It contains #ActivityRecord objects.
      */
-    final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
+    private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
 
     /**
      * Used for validating app tokens with window manager.
@@ -290,6 +296,12 @@
     private ActivityRecord mLastScreenshotActivity = null;
     private Bitmap mLastScreenshotBitmap = null;
 
+    /**
+     * List of ActivityRecord objects that have been finished and must
+     * still report back to a pending thumbnail receiver.
+     */
+    private final ArrayList<ActivityRecord> mCancelledThumbnails = new ArrayList<ActivityRecord>();
+
     int mThumbnailWidth = -1;
     int mThumbnailHeight = -1;
 
@@ -491,14 +503,10 @@
         return null;
     }
 
-    final int indexOfTokenLocked(IBinder token) {
+    private final int indexOfTokenLocked(IBinder token) {
         return mHistory.indexOf(ActivityRecord.forToken(token));
     }
 
-    final int indexOfActivityLocked(ActivityRecord r) {
-        return mHistory.indexOf(r);
-    }
-
     final ActivityRecord isInStackLocked(IBinder token) {
         ActivityRecord r = ActivityRecord.forToken(token);
         if (mHistory.contains(r)) {
@@ -507,6 +515,23 @@
         return null;
     }
 
+    int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+        TaskRecord lastTask = null;
+        final int N = mHistory.size();
+        for (int i = 0; i < N; i++) {
+            ActivityRecord r = mHistory.get(i);
+            if (r.appToken == token) {
+                if (!onlyRoot || lastTask != r.task) {
+                    return r.task.taskId;
+                }
+                return -1;
+            }
+            lastTask = r.task;
+        }
+
+        return -1;
+    }
+
     private final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -710,7 +735,13 @@
                 try {
                     profileFd = profileFd.dup();
                 } catch (IOException e) {
-                    profileFd = null;
+                    if (profileFd != null) {
+                        try {
+                            profileFd.close();
+                        } catch (IOException o) {
+                        }
+                        profileFd = null;
+                    }
                 }
             }
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
@@ -1723,7 +1754,7 @@
             
             try {
                 // Deliver all pending results.
-                ArrayList a = next.results;
+                ArrayList<ResultInfo> a = next.results;
                 if (a != null) {
                     final int N = a.size();
                     if (!next.finishing && N > 0) {
@@ -2121,6 +2152,7 @@
                             }
                             i++;
                         }
+                        mService.mWindowManager.moveTaskToBottom(target.task.taskId);
                         if (taskTop == p) {
                             taskTop = below;
                         }
@@ -2269,6 +2301,8 @@
                             validateAppTokensLocked();
                         }
                     }
+                    // TODO: This is wrong because it doesn't take lastReparentPos into account.
+                    mService.mWindowManager.moveTaskToTop(task.taskId);
                     replyChainEnd = -1;
                     
                     // Now we've moved it in to place...  but what if this is
@@ -2378,7 +2412,7 @@
                 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                         && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                     if (!ret.finishing) {
-                        int index = indexOfTokenLocked(ret.appToken);
+                        int index = mHistory.indexOf(ret);
                         if (index >= 0) {
                             finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
                                     null, "clear", false);
@@ -3533,7 +3567,7 @@
             }
 
             // Get the activity record.
-            int index = indexOfActivityLocked(r);
+            int index = mHistory.indexOf(r);
             if (index >= 0) {
                 res = r;
 
@@ -3589,9 +3623,9 @@
                 finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
                 mFinishingActivities.clear();
             }
-            if ((NT=mService.mCancelledThumbnails.size()) > 0) {
-                thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
-                mService.mCancelledThumbnails.clear();
+            if ((NT=mCancelledThumbnails.size()) > 0) {
+                thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
+                mCancelledThumbnails.clear();
             }
 
             if (mMainStack) {
@@ -3619,7 +3653,7 @@
         // Stop any activities that are scheduled to do so but have been
         // waiting for the next one to start.
         for (i=0; i<NS; i++) {
-            ActivityRecord r = (ActivityRecord)stops.get(i);
+            ActivityRecord r = stops.get(i);
             synchronized (mService) {
                 if (r.finishing) {
                     finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
@@ -3632,7 +3666,7 @@
         // Finish any activities that are scheduled to do so but have been
         // waiting for the next one to start.
         for (i=0; i<NF; i++) {
-            ActivityRecord r = (ActivityRecord)finishes.get(i);
+            ActivityRecord r = finishes.get(i);
             synchronized (mService) {
                 activityRemoved = destroyActivityLocked(r, true, false, "finish-idle");
             }
@@ -3640,7 +3674,7 @@
 
         // Report back to any thumbnail receivers.
         for (i=0; i<NT; i++) {
-            ActivityRecord r = (ActivityRecord)thumbnails.get(i);
+            ActivityRecord r = thumbnails.get(i);
             mService.sendPendingThumbnail(r, null, null, null, true);
         }
 
@@ -3695,7 +3729,7 @@
 
         int i;
         for (i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.resultTo == self && r.requestCode == requestCode) {
                 if ((r.resultWho == null && resultWho == null) ||
                     (r.resultWho != null && r.resultWho.equals(resultWho))) {
@@ -3707,6 +3741,36 @@
         mService.updateOomAdjLocked();
     }
 
+    final void finishTopRunningActivityLocked(ProcessRecord app) {
+        ActivityRecord r = topRunningActivityLocked(null);
+        if (r != null && r.app == app) {
+            // If the top running activity is from this crashing
+            // process, then terminate it to avoid getting in a loop.
+            Slog.w(TAG, "  Force finishing activity "
+                    + r.intent.getComponent().flattenToShortString());
+            int index = mHistory.indexOf(r);
+            r.stack.finishActivityLocked(r, index,
+                    Activity.RESULT_CANCELED, null, "crashed", false);
+            // Also terminate any activities below it that aren't yet
+            // stopped, to avoid a situation where one will get
+            // re-start our crashing activity once it gets resumed again.
+            index--;
+            if (index >= 0) {
+                r = mHistory.get(index);
+                if (r.state == ActivityState.RESUMED
+                        || r.state == ActivityState.PAUSING
+                        || r.state == ActivityState.PAUSED) {
+                    if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
+                        Slog.w(TAG, "  Force finishing activity "
+                                + r.intent.getComponent().flattenToShortString());
+                        r.stack.finishActivityLocked(r, index,
+                                Activity.RESULT_CANCELED, null, "crashed", false);
+                    }
+                }
+            }
+        }
+    }
+
     final boolean finishActivityAffinityLocked(IBinder token) {
         int index = indexOfTokenLocked(token);
         if (DEBUG_RESULTS) Slog.v(
@@ -3765,6 +3829,19 @@
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
+    final boolean finishActivityLocked(ActivityRecord r,
+            int resultCode, Intent resultData, String reason, boolean oomAdj) {
+        int index = mHistory.indexOf(r);
+        if (index >= 0) {
+            return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
+        }
+        return false;
+    }
+
+    /**
+     * @return Returns true if this activity has been removed from the history
+     * list, or false if it is still in the list and will be removed later.
+     */
     final boolean finishActivityLocked(ActivityRecord r, int index,
             int resultCode, Intent resultData, String reason, boolean oomAdj) {
         return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
@@ -3814,7 +3891,7 @@
             // There are clients waiting to receive thumbnails so, in case
             // this is an activity that someone is waiting for, add it
             // to the pending list so we can correctly update the clients.
-            mService.mCancelledThumbnails.add(r);
+            mCancelledThumbnails.add(r);
         }
 
         if (immediate) {
@@ -3857,7 +3934,7 @@
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
             int mode, boolean oomAdj) {
-        final int index = indexOfActivityLocked(r);
+        final int index = mHistory.indexOf(r);
         if (index < 0) {
             return null;
         }
@@ -3913,16 +3990,102 @@
                 resumeTopActivityLocked(null);
             }
             return activityRemoved ? null : r;
-        } else {
-            // Need to go through the full pause cycle to get this
-            // activity into the stopped state and then finish it.
-            if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
-            mFinishingActivities.add(r);
-            resumeTopActivityLocked(null);
         }
+
+        // Need to go through the full pause cycle to get this
+        // activity into the stopped state and then finish it.
+        if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+        mFinishingActivities.add(r);
+        resumeTopActivityLocked(null);
         return r;
     }
 
+    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+            Intent resultData) {
+        final int start = mHistory.indexOf(srec);
+        if (start < 0) {
+            // Current activity is not in history stack; do nothing.
+            return false;
+        }
+        int finishTo = start - 1;
+        ActivityRecord parent = null;
+        boolean foundParentInTask = false;
+        ComponentName dest = destIntent.getComponent();
+        if (dest != null) {
+            TaskRecord tr = srec.task;
+            for (int i = start - 1; i >= 0; i--) {
+                ActivityRecord r = mHistory.get(i);
+                if (tr != r.task) {
+                    // Couldn't find parent in the same task; stop at the one above this.
+                    // (Root of current task; in-app "home" behavior)
+                    // Always at least finish the current activity.
+                    finishTo = Math.min(start - 1, i + 1);
+                    parent = mHistory.get(finishTo);
+                    break;
+                } else if (r.info.packageName.equals(dest.getPackageName()) &&
+                        r.info.name.equals(dest.getClassName())) {
+                    finishTo = i;
+                    parent = r;
+                    foundParentInTask = true;
+                    break;
+                }
+            }
+        }
+
+        IActivityController controller = mService.mController;
+        if (controller != null) {
+            ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+            if (next != null) {
+                // ask watcher if this is allowed
+                boolean resumeOK = true;
+                try {
+                    resumeOK = controller.activityResuming(next.packageName);
+                } catch (RemoteException e) {
+                    mService.mController = null;
+                }
+
+                if (!resumeOK) {
+                    return false;
+                }
+            }
+        }
+        final long origId = Binder.clearCallingIdentity();
+        for (int i = start; i > finishTo; i--) {
+            ActivityRecord r = mHistory.get(i);
+            requestFinishActivityLocked(r.appToken, resultCode, resultData,
+                    "navigate-up", true);
+            // Only return the supplied result for the first activity finished
+            resultCode = Activity.RESULT_CANCELED;
+            resultData = null;
+        }
+
+        if (parent != null && foundParentInTask) {
+            final int parentLaunchMode = parent.info.launchMode;
+            final int destIntentFlags = destIntent.getFlags();
+            if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+                    parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+                    (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+                parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+            } else {
+                try {
+                    ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+                            destIntent.getComponent(), 0, srec.userId);
+                    int res = startActivityLocked(srec.app.thread, destIntent,
+                            null, aInfo, parent.appToken, null,
+                            0, -1, parent.launchedFromUid, parent.launchedFromPackage,
+                            0, null, true, null);
+                    foundParentInTask = res == ActivityManager.START_SUCCESS;
+                } catch (RemoteException e) {
+                    foundParentInTask = false;
+                }
+                requestFinishActivityLocked(parent.appToken, resultCode,
+                        resultData, "navigate-up", true);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+        return foundParentInTask;
+    }
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
@@ -3974,7 +4137,7 @@
             // There are clients waiting to receive thumbnails so, in case
             // this is an activity that someone is waiting for, add it
             // to the pending list so we can correctly update the clients.
-            mService.mCancelledThumbnails.add(r);
+            mCancelledThumbnails.add(r);
         }
 
         // Get rid of any pending idle timeouts.
@@ -4181,7 +4344,7 @@
                     mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
                 }
 
-                int index = indexOfActivityLocked(r);
+                int index = mHistory.indexOf(r);
                 if (index >= 0) {
                     if (r.state == ActivityState.DESTROYING) {
                         cleanUpActivityLocked(r, true, false);
@@ -4195,15 +4358,15 @@
         }
     }
     
-    private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app,
-            String listName) {
+    private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+            ProcessRecord app, String listName) {
         int i = list.size();
         if (DEBUG_CLEANUP) Slog.v(
             TAG, "Removing app " + app + " from list " + listName
             + " with " + i + " entries");
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)list.get(i);
+            ActivityRecord r = list.get(i);
             if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
             if (r.app == app) {
                 if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
@@ -4229,7 +4392,7 @@
             TAG, "Removing app " + app + " from history with " + i + " entries");
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (DEBUG_CLEANUP) Slog.v(
                 TAG, "Record #" + i + " " + r + ": app=" + r.app);
             if (r.app == app) {
@@ -4322,6 +4485,25 @@
         mService.mWindowManager.prepareAppTransition(transit, false);
     }
 
+    final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
+        for (int i = mHistory.size() - 1; i >= 0; i--) {
+            ActivityRecord hr = mHistory.get(i);
+            if (hr.task.taskId == taskId) {
+                if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+                    mUserLeaving = true;
+                }
+                if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
+                    // Caller wants the home activity moved with it.  To accomplish this,
+                    // we'll just move the home task to the top first.
+                    moveHomeToFrontLocked();
+                }
+                moveTaskToFrontLocked(hr.task, null, options);
+                return true;
+            }
+        }
+        return false;
+    }
+
     final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
         if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
@@ -4386,6 +4568,7 @@
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
+        mService.mWindowManager.moveTaskToTop(task);
 
         finishTaskMoveLocked(task);
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
@@ -4478,6 +4661,7 @@
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
+        mService.mWindowManager.moveTaskToBottom(task);
 
         finishTaskMoveLocked(task);
         return true;
@@ -4507,9 +4691,8 @@
         TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
         if (info.numSubThumbbails <= 0) {
             return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
-        } else {
-            return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
         }
+        return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
     }
 
     public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
@@ -4589,6 +4772,7 @@
         }
         if (thumbs.numSubThumbbails > 0) {
             thumbs.retriever = new IThumbnailRetriever.Stub() {
+                @Override
                 public Bitmap getThumbnail(int index) {
                     if (index < 0 || index >= thumbs.subtasks.size()) {
                         return null;
@@ -4787,4 +4971,204 @@
     public void dismissKeyguardOnNextActivityLocked() {
         mDismissKeyguardOnNextActivity = true;
     }
+
+    boolean willActivityBeVisibleLocked(IBinder token) {
+        int i;
+        for (i = mHistory.size() - 1; i >= 0; i--) {
+            ActivityRecord r = mHistory.get(i);
+            if (r.appToken == token) {
+                    return true;
+            }
+            if (r.fullscreen && !r.finishing) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void closeSystemDialogsLocked() {
+        for (int i = mHistory.size() - 1; i >= 0; i--) {
+            ActivityRecord r = mHistory.get(i);
+            if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+                r.stack.finishActivityLocked(r, i,
+                        Activity.RESULT_CANCELED, null, "close-sys", true);
+            }
+        }
+    }
+
+    boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
+        boolean didSomething = false;
+        TaskRecord lastTask = null;
+        final int N = mHistory.size();
+        for (int i = 0; i < N; i++) {
+            ActivityRecord r = mHistory.get(i);
+            final boolean samePackage = r.packageName.equals(name)
+                    || (name == null && r.userId == userId);
+            if ((userId == UserHandle.USER_ALL || r.userId == userId)
+                    && (samePackage || r.task == lastTask)
+                    && (r.app == null || evenPersistent || !r.app.persistent)) {
+                if (!doit) {
+                    if (r.finishing) {
+                        // If this activity is just finishing, then it is not
+                        // interesting as far as something to stop.
+                        continue;
+                    }
+                    return true;
+                }
+                didSomething = true;
+                Slog.i(TAG, "  Force finishing activity " + r);
+                if (samePackage) {
+                    if (r.app != null) {
+                        r.app.removed = true;
+                    }
+                    r.app = null;
+                }
+                lastTask = r.task;
+                if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                        null, "force-stop", true)) {
+                    i--;
+                }
+            }
+        }
+        return didSomething;
+    }
+
+    ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
+        PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
+        ActivityRecord topRecord = null;
+        int pos = mHistory.size() - 1;
+        ActivityRecord next = pos >= 0 ? mHistory.get(pos) : null;
+        ActivityRecord top = null;
+        TaskRecord curTask = null;
+        int numActivities = 0;
+        int numRunning = 0;
+        while (pos >= 0 && maxNum > 0) {
+            final ActivityRecord r = next;
+            pos--;
+            next = pos >= 0 ? mHistory.get(pos) : null;
+
+            // Initialize state for next task if needed.
+            if (top == null || (top.state == ActivityState.INITIALIZING && top.task == r.task)) {
+                top = r;
+                curTask = r.task;
+                numActivities = numRunning = 0;
+            }
+
+            // Add 'r' into the current task.
+            numActivities++;
+            if (r.app != null && r.app.thread != null) {
+                numRunning++;
+            }
+
+            if (localLOGV) Slog.v(
+                TAG, r.intent.getComponent().flattenToShortString()
+                + ": task=" + r.task);
+
+            // If the next one is a different task, generate a new
+            // TaskInfo entry for what we have.
+            if (next == null || next.task != curTask) {
+                RunningTaskInfo ci = new RunningTaskInfo();
+                ci.id = curTask.taskId;
+                ci.baseActivity = r.intent.getComponent();
+                ci.topActivity = top.intent.getComponent();
+                if (top.thumbHolder != null) {
+                    ci.description = top.thumbHolder.lastDescription;
+                }
+                ci.numActivities = numActivities;
+                ci.numRunning = numRunning;
+                //System.out.println(
+                //    "#" + maxNum + ": " + " descr=" + ci.description);
+                if (receiver != null) {
+                    if (localLOGV) Slog.v(
+                        TAG, "State=" + top.state + "Idle=" + top.idle
+                        + " app=" + top.app
+                        + " thr=" + (top.app != null ? top.app.thread : null));
+                    if (top.state == ActivityState.RESUMED || top.state == ActivityState.PAUSING) {
+                        if (top.idle && top.app != null && top.app.thread != null) {
+                            topRecord = top;
+                        } else {
+                            top.thumbnailNeeded = true;
+                        }
+                    }
+                    pending.pendingRecords.add(top);
+                }
+                list.add(ci);
+                maxNum--;
+                top = null;
+            }
+        }
+        return topRecord;
+    }
+
+    public void unhandledBackLocked() {
+        int top = mHistory.size() - 1;
+        if (DEBUG_SWITCH) Slog.d(
+            TAG, "Performing unhandledBack(): top activity at " + top);
+        if (top > 0) {
+            finishActivityLocked(mHistory.get(top),
+                        top, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+        }
+    }
+
+    void handleAppCrashLocked(ProcessRecord app) {
+        for (int i = mHistory.size() - 1; i >= 0; i--) {
+            ActivityRecord r = mHistory.get(i);
+            if (r.app == app) {
+                Slog.w(TAG, "  Force finishing activity "
+                    + r.intent.getComponent().flattenToShortString());
+                r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                        null, "crashed", false);
+            }
+        }
+    }
+
+    void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+            boolean dumpClient, String dumpPackage) {
+        ActivityManagerService.dumpHistoryList(fd, pw, mHistory, "  ", "Hist", true, !dumpAll,
+            dumpClient, dumpPackage);
+    }
+
+    ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
+        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+
+        if ("all".equals(name)) {
+            for (ActivityRecord r1 : mHistory) {
+                activities.add(r1);
+            }
+        } else if ("top".equals(name)) {
+            final int N = mHistory.size();
+            if (N > 0) {
+                activities.add(mHistory.get(N-1));
+            }
+        } else {
+            ItemMatcher matcher = new ItemMatcher();
+            matcher.build(name);
+
+            for (ActivityRecord r1 : mHistory) {
+                if (matcher.match(r1, r1.intent.getComponent())) {
+                    activities.add(r1);
+                }
+            }
+        }
+
+        return activities;
+    }
+
+    ActivityRecord restartPackage(String packageName) {
+        ActivityRecord starting = topRunningActivityLocked(null);
+
+        // All activities that came from the package must be
+        // restarted as if there was a config change.
+        for (int i = mHistory.size() - 1; i >= 0; i--) {
+            ActivityRecord a = mHistory.get(i);
+            if (a.info.packageName.equals(packageName)) {
+                a.forceNewConfig = true;
+                if (starting != null && a == starting && a.visible) {
+                    a.startFreezingScreenLocked(starting.app, ActivityInfo.CONFIG_SCREEN_LAYOUT);
+                }
+            }
+        }
+
+        return starting;
+    }
 }
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 3a6492e..863bdad 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -295,20 +295,8 @@
             Message msg = mHandler.obtainMessage(MSG_WRITE);
             mHandler.sendMessageDelayed(msg, 10000);
 
-            ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
-
-            // All activities that came from the package must be
-            // restarted as if there was a config change.
-            for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
-                ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
-                if (a.info.packageName.equals(packageName)) {
-                    a.forceNewConfig = true;
-                    if (starting != null && a == starting && a.visible) {
-                        a.startFreezingScreenLocked(starting.app,
-                                ActivityInfo.CONFIG_SCREEN_LAYOUT);
-                    }
-                }
-            }
+            
+            ActivityRecord starting = mService.mMainStack.restartPackage(packageName);
 
             // Tell all processes that loaded this package about the change.
             for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/java/com/android/server/am/PendingThumbnailsRecord.java
index ed478c9..c460791 100644
--- a/services/java/com/android/server/am/PendingThumbnailsRecord.java
+++ b/services/java/com/android/server/am/PendingThumbnailsRecord.java
@@ -27,13 +27,13 @@
 class PendingThumbnailsRecord
 {
     final IThumbnailReceiver receiver;   // who is waiting.
-    HashSet pendingRecords; // HistoryRecord objects we still wait for.
+    final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for.
     boolean finished;       // Is pendingRecords empty?
 
     PendingThumbnailsRecord(IThumbnailReceiver _receiver)
     {
         receiver = _receiver;
-        pendingRecords = new HashSet();
+        pendingRecords = new HashSet<ActivityRecord>();
         finished = false;
     }
 }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 46d2cca..5f44ff4 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -110,6 +110,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.Environment.UserEnvironment;
 import android.security.SystemKeyStore;
 import android.util.DisplayMetrics;
@@ -185,6 +186,7 @@
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
     private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
+    private static final int SHELL_UID = Process.SHELL_UID;
 
     private static final boolean GET_CERTIFICATES = true;
 
@@ -974,6 +976,7 @@
         mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
         mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
         mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);
+        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM);
 
         String separateProcesses = SystemProperties.get("debug.separate_processes");
         if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -5649,6 +5652,14 @@
                 null);
 
         final int uid = Binder.getCallingUid();
+        if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+            try {
+                observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
+            } catch (RemoteException re) {
+            }
+            return;
+        }
+
         UserHandle user;
         if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
             user = UserHandle.ALL;
@@ -5685,6 +5696,9 @@
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(uid);
+        if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+            return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
+        }
 
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -5715,7 +5729,19 @@
 
         return PackageManager.INSTALL_SUCCEEDED;
     }
-    
+
+    private boolean isUserAllowed(int callingUid, String restrictionKey) {
+        if (callingUid != android.os.Process.myUid()) {
+            Bundle restrictions = sUserManager.getUserRestrictions(
+                    UserHandle.getUserId(callingUid));
+            if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
+                Log.w(TAG, "User does not have permission to: " + restrictionKey);
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
@@ -8071,6 +8097,14 @@
                 android.Manifest.permission.DELETE_PACKAGES, null);
         // Queue up an async operation since the package deletion may take a little while.
         final int uid = Binder.getCallingUid();
+        if (!isUserAllowed(uid, UserManager.ALLOW_UNINSTALL_APPS)) {
+            try {
+                observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
+            } catch (RemoteException re) {
+            }
+            return;
+        }
+
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index dbfe34d..18ccf75 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -30,6 +30,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -81,6 +82,7 @@
     private static final String ATTR_USER_VERSION = "version";
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
+    private static final String TAG_RESTRICTIONS = "restrictions";
 
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
@@ -104,6 +106,7 @@
     private final File mBaseUserPath;
 
     private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+    private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>();
 
     /**
      * Set of user IDs being actively removed. Removed IDs linger in this set
@@ -343,6 +346,26 @@
         }
     }
 
+    @Override
+    public Bundle getUserRestrictions(int userId) {
+        // checkManageUsersPermission("getUserRestrictions");
+
+        synchronized (mPackagesLock) {
+            Bundle restrictions = mUserRestrictions.get(userId);
+            return restrictions != null ? restrictions : Bundle.EMPTY;
+        }
+    }
+
+    @Override
+    public void setUserRestrictions(Bundle restrictions, int userId) {
+        checkManageUsersPermission("setUserRestrictions");
+
+        synchronized (mPackagesLock) {
+            mUserRestrictions.get(userId).putAll(restrictions);
+            writeUserLocked(mUsers.get(userId));
+        }
+    }
+
     /**
      * Check if we've hit the limit of how many users can be created.
      */
@@ -454,7 +477,7 @@
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
                     String id = parser.getAttributeValue(null, ATTR_ID);
-                    UserInfo user = readUser(Integer.parseInt(id));
+                    UserInfo user = readUserLocked(Integer.parseInt(id));
 
                     if (user != null) {
                         mUsers.put(user.id, user);
@@ -524,6 +547,11 @@
                 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
         mUsers.put(0, primary);
         mNextSerialNumber = MIN_USER_ID;
+        
+        Bundle restrictions = new Bundle();
+        initRestrictionsToDefaults(restrictions);
+        mUserRestrictions.append(0, restrictions);
+        
         updateUserIdsLocked();
 
         writeUserListLocked();
@@ -568,6 +596,15 @@
             serializer.text(userInfo.name);
             serializer.endTag(null, TAG_NAME);
 
+            Bundle restrictions = mUserRestrictions.get(userInfo.id);
+            if (restrictions != null) {
+                serializer.startTag(null, TAG_RESTRICTIONS);
+                writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_WIFI);
+                writeBoolean(serializer, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
+                writeBoolean(serializer, restrictions, UserManager.ALLOW_INSTALL_APPS);
+                writeBoolean(serializer, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
+                serializer.endTag(null, TAG_RESTRICTIONS);
+            }
             serializer.endTag(null, TAG_USER);
 
             serializer.endDocument();
@@ -620,7 +657,7 @@
         }
     }
 
-    private UserInfo readUser(int id) {
+    private UserInfo readUserLocked(int id) {
         int flags = 0;
         int serialNumber = id;
         String name = null;
@@ -628,6 +665,8 @@
         long creationTime = 0L;
         long lastLoggedInTime = 0L;
         boolean partial = false;
+        Bundle restrictions = new Bundle();
+        initRestrictionsToDefaults(restrictions);
 
         FileInputStream fis = null;
         try {
@@ -663,13 +702,23 @@
                     partial = true;
                 }
 
-                while ((type = parser.next()) != XmlPullParser.START_TAG
-                        && type != XmlPullParser.END_DOCUMENT) {
-                }
-                if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {
-                    type = parser.next();
-                    if (type == XmlPullParser.TEXT) {
-                        name = parser.getText();
+                int outerDepth = parser.getDepth();
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                       && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
+                    String tag = parser.getName();
+                    if (TAG_NAME.equals(tag)) {
+                        type = parser.next();
+                        if (type == XmlPullParser.TEXT) {
+                            name = parser.getText();
+                        }
+                    } else if (TAG_RESTRICTIONS.equals(tag)) {
+                        readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_WIFI);
+                        readBoolean(parser, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
+                        readBoolean(parser, restrictions, UserManager.ALLOW_INSTALL_APPS);
+                        readBoolean(parser, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
                     }
                 }
             }
@@ -679,6 +728,7 @@
             userInfo.creationTime = creationTime;
             userInfo.lastLoggedInTime = lastLoggedInTime;
             userInfo.partial = partial;
+            mUserRestrictions.append(id, restrictions);
             return userInfo;
 
         } catch (IOException ioe) {
@@ -694,6 +744,27 @@
         return null;
     }
 
+    private void readBoolean(XmlPullParser parser, Bundle restrictions,
+            String restrictionKey) {
+        String value = parser.getAttributeValue(null, restrictionKey);
+        restrictions.putBoolean(restrictionKey, value == null ? true : Boolean.parseBoolean(value));
+    }
+
+    private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey)
+            throws IOException {
+        if (restrictions.containsKey(restrictionKey)) {
+            xml.attribute(null, restrictionKey,
+                    Boolean.toString(restrictions.getBoolean(restrictionKey)));
+        }
+    }
+
+    private void initRestrictionsToDefaults(Bundle restrictions) {
+        restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
+        restrictions.putBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS, true);
+        restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, true);
+        restrictions.putBoolean(UserManager.ALLOW_UNINSTALL_APPS, true);
+    }
+
     private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
         String valueString = parser.getAttributeValue(null, attr);
         if (valueString == null) return defaultValue;
@@ -739,6 +810,9 @@
                     userInfo.partial = false;
                     writeUserLocked(userInfo);
                     updateUserIdsLocked();
+                    Bundle restrictions = new Bundle();
+                    initRestrictionsToDefaults(restrictions);
+                    mUserRestrictions.append(userId, restrictions);
                 }
             }
             if (userInfo != null) {
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 906ea57..43a5f0c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,12 +16,16 @@
 
 package com.android.server.wm;
 
+import android.os.Debug;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 
 class DisplayContentList extends ArrayList<DisplayContent> {
 }
@@ -34,7 +38,7 @@
  * WindowManagerService.mWindowMap.
  */
 class DisplayContent {
-//    private final static String TAG = "DisplayContent";
+    private final static String TAG = "DisplayContent";
 
     /** Unique identifier of this stack. */
     private final int mDisplayId;
@@ -97,7 +101,7 @@
     /**
      * Sorted most recent at top, oldest at [0].
      */
-//    ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
+    ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
     SparseArray<TaskList> mTaskIdToTaskList = new SparseArray<TaskList>();
 
     /**
@@ -133,24 +137,28 @@
     /**
      *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
      * @param addPos The location the token was inserted into in mAppTokens.
-     * @param atoken The token to insert.
+     * @param wtoken The token to insert.
      */
-    void addAppToken(final int addPos, final AppWindowToken atoken) {
-        mAppTokens.add(addPos, atoken);
+    void addAppToken(final int addPos, final AppWindowToken wtoken) {
+        mAppTokens.add(addPos, wtoken);
 
         if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
             // It was inserted into the beginning or end of mAppTokens. Honor that.
-            mAnimatingAppTokens.add(addPos, atoken);
+            mAnimatingAppTokens.add(addPos, wtoken);
         } else {
             // Find the item immediately above the mAppTokens insertion point and put the token
             // immediately below that one in mAnimatingAppTokens.
             final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
-            mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
+            mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
         }
 
-        TaskList task = mTaskIdToTaskList.get(atoken.groupId);
+        TaskList task = mTaskIdToTaskList.get(wtoken.groupId);
         if (task == null) {
-            mTaskIdToTaskList.put(atoken.groupId, new TaskList(atoken));
+            task = new TaskList(wtoken, this);
+            mTaskIdToTaskList.put(wtoken.groupId, task);
+            mTaskLists.add(task);
+        } else {
+            task.mAppTokens.add(wtoken);
         }
     }
 
@@ -163,6 +171,7 @@
             AppTokenList appTokens = task.mAppTokens;
             appTokens.remove(wtoken);
             if (appTokens.size() == 0) {
+                mTaskLists.remove(task);
                 mTaskIdToTaskList.delete(taskId);
             }
         }
@@ -186,7 +195,7 @@
 
         task = mTaskIdToTaskList.get(newTaskId);
         if (task == null) {
-            task = new TaskList(wtoken);
+            task = new TaskList(wtoken, this);
             mTaskIdToTaskList.put(newTaskId, task);
         } else {
             task.mAppTokens.add(wtoken);
@@ -195,6 +204,122 @@
         wtoken.groupId = newTaskId;
     }
 
+    class TaskListsIterator implements Iterator<TaskList> {
+        private int mCur;
+        private boolean mReverse;
+
+        TaskListsIterator() {
+            this(false);
+        }
+
+        TaskListsIterator(boolean reverse) {
+            mReverse = reverse;
+            int numTaskLists = mTaskLists.size();
+            mCur = reverse ? numTaskLists - 1 : 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskLists.size();
+        }
+
+        @Override
+        public TaskList next() {
+            if (hasNext()) {
+                TaskList taskList = mTaskLists.get(mCur);
+                mCur += (mReverse ? -1 : 1);
+                return taskList;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    class AppTokenIterator implements Iterator<AppWindowToken> {
+        final TaskListsIterator mIterator;
+        final boolean mReverse;
+        int mCur;
+        TaskList mTaskList;
+
+        public AppTokenIterator() {
+            this(false);
+        }
+
+        public AppTokenIterator(boolean reverse) {
+            mReverse = reverse;
+            mIterator = new TaskListsIterator(reverse);
+            getNextTaskList();
+        }
+
+        private void getNextTaskList() {
+            if (mIterator.hasNext()) {
+                mTaskList = mIterator.next();
+                mCur = mReverse ? mTaskList.mAppTokens.size() - 1 : 0;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mTaskList == null) {
+                return false;
+            }
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskList.mAppTokens.size();
+        }
+
+        @Override
+        public AppWindowToken next() {
+            if (hasNext()) {
+                AppWindowToken wtoken = mTaskList.mAppTokens.get(mCur);
+                mCur += mReverse ? -1 : 1;
+                if (!hasNext()) {
+                    getNextTaskList();
+                }
+                return wtoken;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    void verifyAppTokens() {
+        AppTokenIterator iterator = new AppTokenIterator();
+        for (int i = 0; i < mAppTokens.size(); ++i) {
+            if (!iterator.hasNext()) {
+                Slog.e(TAG, "compareAppTokens: More mAppTokens than TaskList tokens. Callers="
+                        + Debug.getCallers(4));
+                while (i < mAppTokens.size()) {
+                    Slog.e(TAG, "compareAppTokens: mAppTokens[" + i + "]=" + mAppTokens.get(i));
+                    i++;
+                }
+                return;
+            }
+            AppWindowToken appToken = mAppTokens.get(i);
+            AppWindowToken taskListToken = iterator.next();
+            if (appToken != taskListToken) {
+                Slog.e(TAG, "compareAppTokens: Mismatch at " + i + " appToken=" + appToken
+                        + " taskListToken=" + taskListToken + ". Callers=" + Debug.getCallers(4));
+            }
+        }
+        if (iterator.hasNext()) {
+            Slog.e(TAG, "compareAppTokens: More TaskList tokens than mAppTokens Callers="
+                    + Debug.getCallers(4));
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
         final String subPrefix = "  " + prefix;
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java
index 6e876f6..61093ad 100644
--- a/services/java/com/android/server/wm/DisplayMagnifier.java
+++ b/services/java/com/android/server/wm/DisplayMagnifier.java
@@ -86,8 +86,8 @@
         mContext = windowManagerService.mContext;
         mWindowManagerService = windowManagerService;
         mCallbacks = callbacks;
-        mMagnifedViewport = new MagnifiedViewport();
         mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+        mMagnifedViewport = new MagnifiedViewport();
         mLongAnimationDuration = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_longAnimTime);
     }
@@ -273,6 +273,7 @@
                             mContext.getResources().getDisplayMetrics());
             mHalfBorderWidth = (int) (mBorderWidth + 0.5) / 2;
             mWindow = new ViewportWindow(mContext);
+            recomputeBoundsLocked();
         }
 
         public void updateMagnificationSpecLocked(MagnificationSpec spec) {
diff --git a/services/java/com/android/server/am/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
similarity index 96%
rename from services/java/com/android/server/am/TaskGroup.java
rename to services/java/com/android/server/wm/TaskGroup.java
index 7574103..5e82af2 100644
--- a/services/java/com/android/server/am/TaskGroup.java
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.am;
+package com.android.server.wm;
 
 import android.view.IApplicationToken;
 
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
index fe12b98..88791f2 100644
--- a/services/java/com/android/server/wm/TaskList.java
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -16,15 +16,15 @@
 
 package com.android.server.wm;
 
-import com.android.server.am.TaskGroup;
-
-class TaskList extends TaskGroup {
+class TaskList {
 //    private final String TAG = "TaskGroup";
-    AppTokenList mAppTokens = new AppTokenList();
+    DisplayContent mDisplayContent;
+    final AppTokenList mAppTokens = new AppTokenList();
+    final int taskId;
 
-    TaskList(AppWindowToken wtoken) {
+    TaskList(AppWindowToken wtoken, DisplayContent displayContent) {
         taskId = wtoken.groupId;
-        tokens.add(wtoken.appToken);
         mAppTokens.add(wtoken);
+        mDisplayContent = displayContent;
     }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 62eccdf..d51c07b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -54,7 +54,6 @@
 import com.android.server.EventLogTags;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.am.TaskGroup;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.power.PowerManagerService;
@@ -330,8 +329,7 @@
     /**
      * Mapping from a token IBinder to a WindowToken object.
      */
-    final HashMap<IBinder, WindowToken> mTokenMap =
-            new HashMap<IBinder, WindowToken>();
+    final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();
 
     /**
      * List of window tokens that have finished starting their application,
@@ -746,6 +744,14 @@
         mActivityManager = ActivityManagerNative.getDefault();
         mBatteryStats = BatteryStatsService.getService();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null,
+                new AppOpsManager.Callback() {
+                    @Override
+                    public void opChanged(int op, String packageName) {
+                        updateAppOpsState();
+                    }
+                }
+        );
 
         // Get persisted window scale setting
         mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
@@ -2150,7 +2156,10 @@
             win.attach();
             mWindowMap.put(client.asBinder(), win);
             if (win.mAppOp != AppOpsManager.OP_NONE) {
-                mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
+                if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
+                        != AppOpsManager.MODE_ALLOWED) {
+                    win.setAppOpVisibilityLw(false);
+                }
             }
 
             if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
@@ -2439,6 +2448,27 @@
         mInputMonitor.updateInputWindowsLw(true /*force*/);
     }
 
+    public void updateAppOpsState() {
+        synchronized(mWindowMap) {
+            boolean changed = false;
+            for (int i=0; i<mDisplayContents.size(); i++) {
+                DisplayContent display = mDisplayContents.valueAt(i);
+                WindowList windows = display.getWindowList();
+                for (int j=0; j<windows.size(); j++) {
+                    final WindowState win = windows.get(j);
+                    if (win.mAppOp != AppOpsManager.OP_NONE) {
+                        changed |= win.setAppOpVisibilityLw(mAppOps.checkOpNoThrow(win.mAppOp,
+                                win.getOwningUid(),
+                                win.getOwningPackage()) == AppOpsManager.MODE_ALLOWED);
+                    }
+                }
+            }
+            if (changed) {
+                scheduleAnimationLocked();
+            }
+        }
+    }
+
     static void logSurface(WindowState w, String msg, RuntimeException where) {
         String str = "  SURFACE " + msg + ": " + w;
         if (where != null) {
@@ -3286,6 +3316,7 @@
                 mTaskIdToDisplayContents.put(taskId, displayContent);
             }
             displayContent.addAppToken(addPos, atoken);
+            displayContent.verifyAppTokens();
             mTokenMap.put(token.asBinder(), atoken);
             mTaskIdToDisplayContents.put(taskId, displayContent);
 
@@ -4269,11 +4300,12 @@
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
                         + " animation=" + wtoken.mAppAnimator.animation
                         + " animating=" + wtoken.mAppAnimator.animating);
+                DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
-                    mTaskIdToDisplayContents.get(wtoken.groupId).mExitingAppTokens.add(wtoken);
+                    displayContent.mExitingAppTokens.add(wtoken);
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
@@ -4283,7 +4315,8 @@
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
-                mTaskIdToDisplayContents.get(wtoken.groupId).removeAppToken(wtoken);
+                displayContent.removeAppToken(wtoken);
+                displayContent.verifyAppTokens();
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4675,6 +4708,44 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    public void moveTaskToTop(int taskId) {
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
+                    + " not found in mTaskIdToDisplayContents");
+            return;
+        }
+        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+        if (taskList == null) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskIdToTaskLists");
+            return;
+        }
+        if (!displayContent.mTaskLists.remove(taskList)) {
+            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskLists");
+        }
+        displayContent.mTaskLists.add(taskList);
+        displayContent.verifyAppTokens();
+    }
+
+    public void moveTaskToBottom(int taskId) {
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
+                    + " not found in mTaskIdToDisplayContents");
+            return;
+        }
+        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+        if (taskList == null) {
+            Slog.e(TAG, "moveTaskToTopBottomtaskId=" + taskId + " not found in mTaskIdToTaskLists");
+            return;
+        }
+        if (!displayContent.mTaskLists.remove(taskList)) {
+            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId + " not found in mTaskLists");
+        }
+        displayContent.mTaskLists.add(0, taskList);
+        displayContent.verifyAppTokens();
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6648e56..8dda544 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -96,6 +96,7 @@
     int mSystemUiVisibility;
     boolean mPolicyVisibility = true;
     boolean mPolicyVisibilityAfterAnim = true;
+    boolean mAppOpVisibility = true;
     boolean mAppFreezing;
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
@@ -982,6 +983,10 @@
                     + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
             return false;
         }
+        if (!mAppOpVisibility) {
+            // Being hidden due to app op request.
+            return false;
+        }
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             // Already showing.
             return false;
@@ -1053,6 +1058,25 @@
         return true;
     }
 
+    public boolean setAppOpVisibilityLw(boolean state) {
+        if (mAppOpVisibility != state) {
+            mAppOpVisibility = state;
+            if (state) {
+                // If the policy visibility had last been to hide, then this
+                // will incorrectly show at this point since we lost that
+                // information.  Not a big deal -- for the windows that have app
+                // ops modifies they should only be hidden by policy due to the
+                // lock screen, and the user won't be changing this if locked.
+                // Plus it will quickly be fixed the next time we do a layout.
+                showLw(true, false);
+            } else {
+                hideLw(true, false);
+            }
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public boolean isAlive() {
         return mClient.asBinder().isBinderAlive();
@@ -1179,11 +1203,14 @@
             pw.print(" mSystemUiVisibility=0x");
             pw.println(Integer.toHexString(mSystemUiVisibility));
         }
-        if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
+        if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
+                || mAttachedHidden) {
             pw.print(prefix); pw.print("mPolicyVisibility=");
                     pw.print(mPolicyVisibility);
                     pw.print(" mPolicyVisibilityAfterAnim=");
                     pw.print(mPolicyVisibilityAfterAnim);
+                    pw.print(" mAppOpVisibility=");
+                    pw.print(mAppOpVisibility);
                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 1758d93..c4911a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -21,8 +21,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
@@ -140,6 +142,20 @@
         }
     }
 
+    public void testRestrictions() {
+        List<UserInfo> users = mUserManager.getUsers();
+        if (users.size() > 1) {
+            Bundle restrictions = new Bundle();
+            restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, false);
+            restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
+            mUserManager.setUserRestrictions(restrictions, new UserHandle(users.get(1).id));
+            Bundle stored = mUserManager.getUserRestrictions(new UserHandle(users.get(1).id));
+            assertEquals(stored.getBoolean(UserManager.ALLOW_CONFIG_WIFI), true);
+            assertEquals(stored.getBoolean(UserManager.ALLOW_UNINSTALL_APPS), true);
+            assertEquals(stored.getBoolean(UserManager.ALLOW_INSTALL_APPS), false);
+        }
+    }
+
     private void removeUser(int userId) {
         synchronized (mUserLock) {
             mUserManager.removeUser(userId);
@@ -151,4 +167,5 @@
             }
         }
     }
+
 }
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 35dea24..d7a58b6 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -26,7 +26,7 @@
 public final class CellInfoLte extends CellInfo implements Parcelable {
 
     private static final String LOG_TAG = "CellInfoLte";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private CellIdentityLte mCellIdentityLte;
     private CellSignalStrengthLte mCellSignalStrengthLte;
diff --git a/tests/BiDiTests/res/layout/canvas.xml b/tests/BiDiTests/res/layout/canvas.xml
deleted file mode 100644
index 0319a83..0000000
--- a/tests/BiDiTests/res/layout/canvas.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/canvas"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent">
-
-        <SeekBar android:id="@+id/seekbar"
-                 android:layout_height="wrap_content"
-                 android:layout_width="match_parent"
-                />
-
-        <view class="com.android.bidi.BiDiTestView"
-              android:id="@+id/testview"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:background="#FF0000"
-                />
-
-    </LinearLayout>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 209597e..b88a885 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -101,7 +101,6 @@
 
         addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
 
-        addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
         addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
 
         addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
deleted file mode 100644
index 33ed731..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Fragment;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SeekBar;
-
-import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
-import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
-
-public class BiDiTestCanvas extends Fragment {
-
-    static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
-
-    private BiDiTestView testView;
-    private SeekBar textSizeSeekBar;
-    private View currentView;
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        currentView = inflater.inflate(R.layout.canvas, container, false);
-        return currentView;
-    }
-
-    @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-
-        testView = (BiDiTestView) currentView.findViewById(R.id.testview);
-        testView.setCurrentTextSize(INIT_TEXT_SIZE);
-
-        textSizeSeekBar = (SeekBar) currentView.findViewById(R.id.seekbar);
-        textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
-        textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
-
-        textSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                testView.setCurrentTextSize(FONT_MIN_SIZE + progress);
-            }
-
-            public void onStartTrackingTouch(SeekBar seekBar) {
-            }
-
-            public void onStopTrackingTouch(SeekBar seekBar) {
-            }
-        });
-    }
-}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
deleted file mode 100644
index 0b1974a..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-public class BiDiTestView extends View {
-
-    private static final String TAG = "BiDiTestView";
-
-    private static final int BORDER_PADDING = 4;
-    private static final int TEXT_PADDING = 16;
-    private static final int TEXT_SIZE = 16;
-    private static final int ORIGIN = 80;
-
-    private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
-
-    private Rect rect = new Rect();
-
-    private String NORMAL_TEXT;
-    private String NORMAL_LONG_TEXT;
-    private String NORMAL_LONG_TEXT_2;
-    private String NORMAL_LONG_TEXT_3;
-    private String ITALIC_TEXT;
-    private String BOLD_TEXT;
-    private String BOLD_ITALIC_TEXT;
-    private String ARABIC_TEXT;
-    private String CHINESE_TEXT;
-    private String MIXED_TEXT_1;
-    private String HEBREW_TEXT;
-    private String RTL_TEXT;
-    private String THAI_TEXT;
-
-    private int currentTextSize;
-
-    public BiDiTestView(Context context) {
-        super(context);
-        init(context);
-    }
-
-    public BiDiTestView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init(context);
-    }
-
-    public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(context);
-    }
-
-    private void init(Context context) {
-        NORMAL_TEXT = context.getString(R.string.normal_text);
-        NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
-        NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2);
-        NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3);
-        ITALIC_TEXT = context.getString(R.string.italic_text);
-        BOLD_TEXT = context.getString(R.string.bold_text);
-        BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
-        ARABIC_TEXT = context.getString(R.string.arabic_text);
-        CHINESE_TEXT = context.getString(R.string.chinese_text);
-        MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
-        HEBREW_TEXT = context.getString(R.string.hebrew_text);
-        RTL_TEXT = context.getString(R.string.rtl);
-        THAI_TEXT = context.getString(R.string.pointer_location);
-    }
-
-    public void setCurrentTextSize(int size) {
-        currentTextSize = size;
-        invalidate();
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        drawInsideRect(canvas, new Paint(), Color.BLACK);
-
-        int deltaX = 0;
-
-        deltaX  = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
-                true, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
-                false, true,  Paint.DIRECTION_LTR, currentTextSize);
-
-        deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
-                true, true,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test with a long string
-        deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test with a long string
-        deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test with a long string
-        deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test Arabic ligature
-        deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
-                false, false,  Paint.DIRECTION_RTL, currentTextSize);
-
-        // Test Chinese
-        deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test Mixed (English and Arabic)
-        deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-
-        // Test Hebrew
-        deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
-                false, false,  Paint.DIRECTION_RTL, currentTextSize);
-
-        // Test Thai
-        deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize,
-                false, false,  Paint.DIRECTION_LTR, currentTextSize);
-    }
-
-    private int testString(Canvas canvas, String text, int x, int y,
-            boolean isItalic, boolean isBold, int dir, int textSize) {
-
-        TextPaint paint = new TextPaint();
-        paint.setAntiAlias(true);
-
-        // Set paint properties
-        boolean oldFakeBold = paint.isFakeBoldText();
-        paint.setFakeBoldText(isBold);
-
-        float oldTextSkewX = paint.getTextSkewX();
-        if (isItalic) {
-            paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
-        }
-
-        paint.setTextSize(textSize);
-        paint.setColor(Color.WHITE);
-        canvas.drawText(text, x, y, paint);
-
-        int length = text.length();
-        float[] advances = new float[length];
-        float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
-        setPaintDir(paint, dir);
-        float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0,
-                1 /* use ICU */);
-
-        logAdvances(text, textWidthHB, textWidthICU, advances);
-        drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
-
-        // Restore old paint properties
-        paint.setFakeBoldText(oldFakeBold);
-        paint.setTextSkewX(oldTextSkewX);
-
-        return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
-    }
-
-    private void setPaintDir(Paint paint, int dir) {
-        Log.v(TAG, "Setting Paint dir=" + dir);
-        paint.setBidiFlags(dir);
-    }
-
-    private void drawInsideRect(Canvas canvas, Paint paint, int color) {
-        paint.setColor(color);
-        int width = getWidth();
-        int height = getHeight();
-        rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
-        canvas.drawRect(rect, paint);
-    }
-
-    private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
-            float textWidthICU, int textSize, int color, int colorICU) {
-        Paint paint = new Paint();
-        paint.setColor(color);
-        canvas.drawLine(x, y - textSize, x, y + 8, paint);
-        canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
-        canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint);
-        paint.setColor(colorICU);
-        canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint);
-    }
-
-    private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) {
-        Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU);
-//        int length = advances.length;
-//        for(int n=0; n<length; n++){
-//            Log.v(TAG, "adv[" + n + "]=" + advances[n]);
-//        }
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
index ddc6a99..3af3745 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
@@ -39,6 +39,7 @@
         typeBuilder.setX(X).setY(Y);
         Allocation A = Allocation.createTyped(RS, typeBuilder.create());
         s.bind_a(A);
+        s.set_aRaw(A);
 
         typeBuilder = new Type.Builder(RS, Element.I32(RS));
         typeBuilder.setX(X).setY(Y).setFaces(true);
@@ -59,6 +60,7 @@
         ScriptC_alloc s = new ScriptC_alloc(pRS);
         pRS.setMessageHandler(mRsMessage);
         initializeGlobals(pRS, s);
+        s.forEach_root(s.get_aRaw());
         s.invoke_alloc_test();
         pRS.finish();
         waitForMessage();
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
index c3f3ca0..fd18f93 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
 
         return;
     }
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
index 653ebd5..13fefe7 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
         s.set_s(s);
         s.set_ain(A);
         s.set_aout(A);
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
index 69fc97f..606af4d 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
 
         return;
     }
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
index 3116e5a..1b5e2ac 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
@@ -5,39 +5,37 @@
 int dimY;
 int dimZ;
 
+rs_allocation aRaw;
 rs_allocation aFaces;
 rs_allocation aLOD;
 rs_allocation aFacesLOD;
 
+void root(int *o, uint32_t x, uint32_t y) {
+    *o = x + y * dimX;
+}
+
 static bool test_alloc_dims() {
     bool failed = false;
     int i, j;
 
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            a[i + j * dimX] = i + j * dimX;
-        }
-    }
-
-    rs_allocation alloc = rsGetAllocation(a);
-    _RS_ASSERT(rsAllocationGetDimX(alloc) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(alloc) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(alloc) == dimZ);
+    _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
+    _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
+    _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
 
     // Test 2D addressing
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
             rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j);
+            const void *p = rsGetElementAt(aRaw, i, j);
             int val = *(const int *)p;
             _RS_ASSERT(val == (i + j * dimX));
         }
     }
 
     // Test 1D addressing
-    for (i = 0; i < dimX * dimY; i++) {
+    for (i = 0; i < dimX; i++) {
         rsDebug("Verifying ", i);
-        const void *p = rsGetElementAt(alloc, i);
+        const void *p = rsGetElementAt(aRaw, i);
         int val = *(const int *)p;
         _RS_ASSERT(val == i);
     }
@@ -46,7 +44,7 @@
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
             rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j, 0);
+            const void *p = rsGetElementAt(aRaw, i, j, 0);
             int val = *(const int *)p;
             _RS_ASSERT(val == (i + j * dimX));
         }
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
index ac527b5..08e6bed 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
@@ -1,6 +1,6 @@
 #include "shared.rsh"
 
-int *a;
+rs_allocation aRaw;
 int dimX;
 int dimY;
 static bool failed = false;
@@ -21,7 +21,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (i + j * dimX));
         }
     }
 
@@ -41,7 +42,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (99 + i + j * dimX));
         }
     }
 
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
index ddf17f8..89df090 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
@@ -1,6 +1,5 @@
 #include "shared.rsh"
 
-int *a;
 int dimX;
 int dimY;
 int xStart = 0;
@@ -9,6 +8,7 @@
 int yEnd = 0;
 
 rs_script s;
+rs_allocation aRaw;
 rs_allocation ain;
 rs_allocation aout;
 
@@ -26,13 +26,14 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
+            int v = rsGetElementAt_int(aRaw, i, j);
             rsDebug("i: ", i);
             rsDebug("j: ", j);
-            rsDebug("a[j][i]: ", a[i + j * dimX]);
+            rsDebug("a[j][i]: ", v);
             if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
-                _RS_ASSERT(a[i + j * dimX] == 0);
+                _RS_ASSERT(v == 0);
             } else {
-                _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+                _RS_ASSERT(v == (i + j * dimX));
             }
         }
     }
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
index 33944aa..2c807bd 100644
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
+++ b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
@@ -1,6 +1,6 @@
 #include "shared.rsh"
 
-int *a;
+rs_allocation aRaw;
 int dimX;
 int dimY;
 static bool failed = false;
@@ -15,7 +15,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (99 + i + j * dimX));
         }
     }
 
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
index a06d820..3ea942c 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
@@ -39,6 +39,7 @@
         typeBuilder.setX(X).setY(Y);
         Allocation A = Allocation.createTyped(RS, typeBuilder.create());
         s.bind_a(A);
+        s.set_aRaw(A);
 
         typeBuilder = new Type.Builder(RS, Element.I32(RS));
         typeBuilder.setX(X).setY(Y).setFaces(true);
@@ -59,6 +60,7 @@
         ScriptC_alloc s = new ScriptC_alloc(pRS);
         pRS.setMessageHandler(mRsMessage);
         initializeGlobals(pRS, s);
+        s.forEach_root(s.get_aRaw());
         s.invoke_alloc_test();
         pRS.finish();
         waitForMessage();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
index 4951970..6c95109 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
 
         return;
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
index bda055b..782f788 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
         s.set_s(s);
         s.set_ain(A);
         s.set_aout(A);
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
index cc48591..69526a8 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
@@ -37,7 +37,7 @@
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
         A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
+        s.set_aRaw(A);
 
         return;
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
index 3116e5a..1b5e2ac 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
@@ -5,39 +5,37 @@
 int dimY;
 int dimZ;
 
+rs_allocation aRaw;
 rs_allocation aFaces;
 rs_allocation aLOD;
 rs_allocation aFacesLOD;
 
+void root(int *o, uint32_t x, uint32_t y) {
+    *o = x + y * dimX;
+}
+
 static bool test_alloc_dims() {
     bool failed = false;
     int i, j;
 
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            a[i + j * dimX] = i + j * dimX;
-        }
-    }
-
-    rs_allocation alloc = rsGetAllocation(a);
-    _RS_ASSERT(rsAllocationGetDimX(alloc) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(alloc) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(alloc) == dimZ);
+    _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
+    _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
+    _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
 
     // Test 2D addressing
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
             rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j);
+            const void *p = rsGetElementAt(aRaw, i, j);
             int val = *(const int *)p;
             _RS_ASSERT(val == (i + j * dimX));
         }
     }
 
     // Test 1D addressing
-    for (i = 0; i < dimX * dimY; i++) {
+    for (i = 0; i < dimX; i++) {
         rsDebug("Verifying ", i);
-        const void *p = rsGetElementAt(alloc, i);
+        const void *p = rsGetElementAt(aRaw, i);
         int val = *(const int *)p;
         _RS_ASSERT(val == i);
     }
@@ -46,7 +44,7 @@
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
             rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j, 0);
+            const void *p = rsGetElementAt(aRaw, i, j, 0);
             int val = *(const int *)p;
             _RS_ASSERT(val == (i + j * dimX));
         }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
index ac527b5..08e6bed 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
@@ -1,6 +1,6 @@
 #include "shared.rsh"
 
-int *a;
+rs_allocation aRaw;
 int dimX;
 int dimY;
 static bool failed = false;
@@ -21,7 +21,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (i + j * dimX));
         }
     }
 
@@ -41,7 +42,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (99 + i + j * dimX));
         }
     }
 
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
index ddf17f8..89df090 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
@@ -1,6 +1,5 @@
 #include "shared.rsh"
 
-int *a;
 int dimX;
 int dimY;
 int xStart = 0;
@@ -9,6 +8,7 @@
 int yEnd = 0;
 
 rs_script s;
+rs_allocation aRaw;
 rs_allocation ain;
 rs_allocation aout;
 
@@ -26,13 +26,14 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
+            int v = rsGetElementAt_int(aRaw, i, j);
             rsDebug("i: ", i);
             rsDebug("j: ", j);
-            rsDebug("a[j][i]: ", a[i + j * dimX]);
+            rsDebug("a[j][i]: ", v);
             if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
-                _RS_ASSERT(a[i + j * dimX] == 0);
+                _RS_ASSERT(v == 0);
             } else {
-                _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+                _RS_ASSERT(v == (i + j * dimX));
             }
         }
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
index 33944aa..2c807bd 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
@@ -1,6 +1,6 @@
 #include "shared.rsh"
 
-int *a;
+rs_allocation aRaw;
 int dimX;
 int dimY;
 static bool failed = false;
@@ -15,7 +15,8 @@
 
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (99 + i + j * dimX));
+            int v = rsGetElementAt_int(aRaw, i, j);
+            _RS_ASSERT(v == (99 + i + j * dimX));
         }
     }
 
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 5b71adc..2149190 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1185,6 +1185,11 @@
         return true;
     }
 
+    if (strcmp(name, "xxxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+        return true;
+    }
+
     char* c = (char*)name;
     while (*c >= '0' && *c <= '9') {
         c++;
diff --git a/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
new file mode 100644
index 0000000..8cd1a69
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+
+
+/**
+ * Delegate used to provide new implementation for the native methods of {@link DateFormat}
+ *
+ * Through the layoutlib_create tool, the original  methods of DateFormat have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class DateFormat_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static boolean is24HourFormat(Context context) {
+        return false;
+    }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 80a1a60..d955040 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -110,6 +110,7 @@
         "android.os.Handler#sendMessageAtTime",
         "android.os.HandlerThread#run",
         "android.os.Build#getString",
+        "android.text.format.DateFormat#is24HourFormat",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
         "android.view.LayoutInflater#rInflate",
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 66c2f3f..eb2f74c 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -35,6 +35,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.UserHandle;
+import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -144,6 +145,7 @@
     private static final String EOS = "eos";
 
     private WifiNative mWifiNative;
+    private final KeyStore mKeyStore = KeyStore.getInstance();
 
     WifiConfigStore(Context c, WifiNative wn) {
         mContext = c;
@@ -295,16 +297,7 @@
     boolean forgetNetwork(int netId) {
         if (mWifiNative.removeNetwork(netId)) {
             mWifiNative.saveConfig();
-            WifiConfiguration target = null;
-            WifiConfiguration config = mConfiguredNetworks.get(netId);
-            if (config != null) {
-                target = mConfiguredNetworks.remove(netId);
-                mNetworkIds.remove(configKey(config));
-            }
-            if (target != null) {
-                writeIpAndProxyConfigurations();
-                sendConfiguredNetworksChangedBroadcast(target, WifiManager.CHANGE_REASON_REMOVED);
-            }
+            removeConfigAndSendBroadcastIfNeeded(netId);
             return true;
         } else {
             loge("Failed to remove network " + netId);
@@ -342,20 +335,27 @@
      */
     boolean removeNetwork(int netId) {
         boolean ret = mWifiNative.removeNetwork(netId);
-        WifiConfiguration config = null;
         if (ret) {
-            config = mConfiguredNetworks.get(netId);
-            if (config != null) {
-                config = mConfiguredNetworks.remove(netId);
-                mNetworkIds.remove(configKey(config));
-            }
-        }
-        if (config != null) {
-            sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
+            removeConfigAndSendBroadcastIfNeeded(netId);
         }
         return ret;
     }
 
+    private void removeConfigAndSendBroadcastIfNeeded(int netId) {
+        WifiConfiguration config = mConfiguredNetworks.get(netId);
+        if (config != null) {
+            // Remove any associated keys
+            if (config.enterpriseConfig != null) {
+                config.enterpriseConfig.removeKeys(mKeyStore);
+            }
+            mConfiguredNetworks.remove(netId);
+            mNetworkIds.remove(configKey(config));
+
+            writeIpAndProxyConfigurations();
+            sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
+        }
+    }
+
     /**
      * Enable a network. Note that there is no saveConfig operation.
      * This function is retained for compatibility with the public
@@ -1090,13 +1090,48 @@
             }
 
             if (config.enterpriseConfig != null) {
-                HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields();
+
+                WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
+
+                if (enterpriseConfig.needsKeyStore()) {
+                    /**
+                     * Keyguard settings may eventually be controlled by device policy.
+                     * We check here if keystore is unlocked before installing
+                     * credentials.
+                     * TODO: Figure a way to store these credentials for wifi alone
+                     * TODO: Do we need a dialog here ?
+                     */
+                    if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
+                        loge(config.SSID + ": key store is locked");
+                        break setVariables;
+                    }
+
+                    try {
+                        /* config passed may include only fields being updated.
+                         * In order to generate the key id, fetch uninitialized
+                         * fields from the currently tracked configuration
+                         */
+                        WifiConfiguration currentConfig = mConfiguredNetworks.get(netId);
+                        String keyId = config.getKeyIdForCredentials(currentConfig);
+
+                        if (!enterpriseConfig.installKeys(mKeyStore, keyId)) {
+                            loge(config.SSID + ": failed to install keys");
+                            break setVariables;
+                        }
+                    } catch (IllegalStateException e) {
+                        loge(config.SSID + " invalid config for key installation");
+                        break setVariables;
+                    }
+                }
+
+                HashMap<String, String> enterpriseFields = enterpriseConfig.getFields();
                 for (String key : enterpriseFields.keySet()) {
                         String value = enterpriseFields.get(key);
                         if (!mWifiNative.setNetworkVariable(
                                     netId,
                                     key,
                                     value)) {
+                            enterpriseConfig.removeKeys(mKeyStore);
                             loge(config.SSID + ": failed to set " + key +
                                     ": " + value);
                             break setVariables;
@@ -1104,7 +1139,7 @@
                 }
             }
             updateFailed = false;
-        }
+        } //end of setVariables
 
         if (updateFailed) {
             if (newNetwork) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 552356c..bf82792 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -19,6 +19,7 @@
 import android.net.LinkProperties;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.text.TextUtils;
 
 import java.util.BitSet;
 
@@ -274,7 +275,8 @@
      */
     public BitSet allowedGroupCiphers;
     /**
-     * The enterprise configuration details
+     * The enterprise configuration details specifying the EAP method,
+     * certificates and other settings associated with the EAP.
      * @hide
      */
     public WifiEnterpriseConfig enterpriseConfig;
@@ -462,6 +464,47 @@
         return SSID;
     }
 
+    /**
+     * Get an identifier for associating credentials with this config
+     * @param current configuration contains values for additional fields
+     *                that are not part of this configuration. Used
+     *                when a config with some fields is passed by an application.
+     * @throws IllegalStateException if config is invalid for key id generation
+     * @hide
+     */
+    String getKeyIdForCredentials(WifiConfiguration current) {
+        String keyMgmt = null;
+
+        try {
+            // Get current config details for fields that are not initialized
+            if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
+            if (allowedKeyManagement.cardinality() == 0) {
+                allowedKeyManagement = current.allowedKeyManagement;
+            }
+            if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+                keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            }
+            if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+                keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
+            }
+
+            if (TextUtils.isEmpty(keyMgmt)) {
+                throw new IllegalStateException("Not an EAP network");
+            }
+
+            return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
+                    trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
+                            current.enterpriseConfig : null));
+        } catch (NullPointerException e) {
+            throw new IllegalStateException("Invalid config details");
+        }
+    }
+
+    private String trimStringForKeyId(String string) {
+        // Remove quotes and spaces
+        return string.replace("\"", "").replace(" ", "");
+    }
+
     private static BitSet readBitSet(Parcel src) {
         int cardinality = src.readInt();
 
@@ -485,6 +528,9 @@
 
     /** @hide */
     public int getAuthType() {
+        if (allowedKeyManagement.cardinality() > 1) {
+            throw new IllegalStateException("More than one auth type set");
+        }
         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
             return KeyMgmt.WPA_PSK;
         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 4dca7ac..7313e7e 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -19,7 +19,26 @@
 import android.os.Parcelable;
 import android.security.Credentials;
 import android.text.TextUtils;
+import android.util.Log;
 
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.org.bouncycastle.asn1.DEROctetString;
+import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -70,6 +89,9 @@
     private static final String PRIVATE_KEY_ID_KEY  = "key_id";
 
     private HashMap<String, String> mFields = new HashMap<String, String>();
+    private X509Certificate mCaCert;
+    private PrivateKey mClientPrivateKey;
+    private X509Certificate mClientCertificate;
 
     /** This represents an empty value of an enterprise field.
      * NULL is used at wpa_supplicant to indicate an empty value
@@ -103,6 +125,34 @@
             dest.writeString(entry.getKey());
             dest.writeString(entry.getValue());
         }
+
+        writeCertificate(dest, mCaCert);
+
+        if (mClientPrivateKey != null) {
+            String algorithm = mClientPrivateKey.getAlgorithm();
+            byte[] userKeyBytes = mClientPrivateKey.getEncoded();
+            dest.writeInt(userKeyBytes.length);
+            dest.writeByteArray(userKeyBytes);
+            dest.writeString(algorithm);
+        } else {
+            dest.writeInt(0);
+        }
+
+        writeCertificate(dest, mClientCertificate);
+    }
+
+    private void writeCertificate(Parcel dest, X509Certificate cert) {
+        if (cert != null) {
+            try {
+                byte[] certBytes = cert.getEncoded();
+                dest.writeInt(certBytes.length);
+                dest.writeByteArray(certBytes);
+            } catch (CertificateEncodingException e) {
+                dest.writeInt(0);
+            }
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     public static final Creator<WifiEnterpriseConfig> CREATOR =
@@ -115,9 +165,47 @@
                         String value = in.readString();
                         enterpriseConfig.mFields.put(key, value);
                     }
+
+                    enterpriseConfig.mCaCert = readCertificate(in);
+
+                    PrivateKey userKey = null;
+                    int len = in.readInt();
+                    if (len > 0) {
+                        try {
+                            byte[] bytes = new byte[len];
+                            in.readByteArray(bytes);
+                            String algorithm = in.readString();
+                            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+                            userKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
+                        } catch (NoSuchAlgorithmException e) {
+                            userKey = null;
+                        } catch (InvalidKeySpecException e) {
+                            userKey = null;
+                        }
+                    }
+
+                    enterpriseConfig.mClientPrivateKey = userKey;
+                    enterpriseConfig.mClientCertificate = readCertificate(in);
                     return enterpriseConfig;
                 }
 
+                private X509Certificate readCertificate(Parcel in) {
+                    X509Certificate cert = null;
+                    int len = in.readInt();
+                    if (len > 0) {
+                        try {
+                            byte[] bytes = new byte[len];
+                            in.readByteArray(bytes);
+                            CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
+                            cert = (X509Certificate) cFactory
+                                    .generateCertificate(new ByteArrayInputStream(bytes));
+                        } catch (CertificateException e) {
+                            cert = null;
+                        }
+                    }
+                    return cert;
+                }
+
                 public WifiEnterpriseConfig[] newArray(int size) {
                     return new WifiEnterpriseConfig[size];
                 }
@@ -145,13 +233,13 @@
         public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" };
     }
 
-    /** Internal use only @hide */
-    public HashMap<String, String> getFields() {
+    /** Internal use only */
+    HashMap<String, String> getFields() {
         return mFields;
     }
 
-    /** Internal use only @hide */
-    public static String[] getSupplicantKeys() {
+    /** Internal use only */
+    static String[] getSupplicantKeys() {
         return new String[] { EAP_KEY, PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY,
                 CLIENT_CERT_KEY, CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY,
                 PRIVATE_KEY_ID_KEY };
@@ -271,28 +359,47 @@
      * a certificate
      * </p>
      * @param alias identifies the certificate
+     * @hide
      */
-    public void setCaCertificate(String alias) {
+    public void setCaCertificateAlias(String alias) {
         setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX);
     }
 
     /**
      * Get CA certificate alias
      * @return alias to the CA certificate
+     * @hide
      */
-    public String getCaCertificate() {
+    public String getCaCertificateAlias() {
         return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
     }
 
     /**
+     * Specify a X.509 certificate that identifies the server.
+     *
+     * <p>A default name is automatically assigned to the certificate and used
+     * with this configuration.
+     * @param cert X.509 CA certificate
+     * @throws IllegalArgumentException if not a CA certificate
+     */
+    public void setCaCertificate(X509Certificate cert) {
+        if (cert.getBasicConstraints() >= 0) {
+            mCaCert = cert;
+        } else {
+            throw new IllegalArgumentException("Not a CA certificate");
+        }
+    }
+
+    /**
      * Set Client certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
      * a certificate
      * </p>
      * @param alias identifies the certificate
+     * @hide
      */
-    public void setClientCertificate(String alias) {
+    public void setClientCertificateAlias(String alias) {
         setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
         setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
         // Also, set engine parameters
@@ -308,12 +415,118 @@
     /**
      * Get client certificate alias
      * @return alias to the client certificate
+     * @hide
      */
-    public String getClientCertificate() {
+    public String getClientCertificateAlias() {
         return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
     }
 
     /**
+     * Specify a private key and client certificate for client authorization.
+     *
+     * <p>A default name is automatically assigned to the key entry and used
+     * with this configuration.
+     * @param privateKey
+     * @param clientCertificate
+     */
+    public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
+        if (clientCertificate != null) {
+            if (clientCertificate.getBasicConstraints() != -1) {
+                throw new IllegalArgumentException("Cannot be a CA certificate");
+            }
+            if (privateKey == null) {
+                throw new IllegalArgumentException("Client cert without a private key");
+            }
+            if (privateKey.getEncoded() == null) {
+                throw new IllegalArgumentException("Private key cannot be encoded");
+            }
+        }
+
+        mClientPrivateKey = privateKey;
+        mClientCertificate = clientCertificate;
+    }
+
+    boolean needsKeyStore() {
+        // Has no keys to be installed
+        if (mClientCertificate == null && mCaCert == null) return false;
+        return true;
+    }
+
+    boolean installKeys(android.security.KeyStore keyStore, String name) {
+        boolean ret = true;
+        String privKeyName = Credentials.USER_PRIVATE_KEY + name;
+        String userCertName = Credentials.USER_CERTIFICATE + name;
+        String caCertName = Credentials.CA_CERTIFICATE + name;
+        if (mClientCertificate != null) {
+            byte[] privKeyData = mClientPrivateKey.getEncoded();
+            ret = keyStore.importKey(privKeyName, privKeyData);
+            if (ret == false) {
+                return ret;
+            }
+
+            ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate);
+            if (ret == false) {
+                // Remove private key installed
+                keyStore.delKey(privKeyName);
+                return ret;
+            }
+        }
+
+        if (mCaCert != null) {
+            ret = putCertInKeyStore(keyStore, caCertName, mCaCert);
+            if (ret == false) {
+                if (mClientCertificate != null) {
+                    // Remove client key+cert
+                    keyStore.delKey(privKeyName);
+                    keyStore.delete(userCertName);
+                }
+                return ret;
+            }
+        }
+
+        // Set alias names
+        if (mClientCertificate != null) {
+            setClientCertificateAlias(name);
+            mClientPrivateKey = null;
+            mClientCertificate = null;
+        }
+
+        if (mCaCert != null) {
+            setCaCertificateAlias(name);
+            mCaCert = null;
+        }
+
+        return ret;
+    }
+
+    private boolean putCertInKeyStore(android.security.KeyStore keyStore, String name,
+            Certificate cert) {
+        try {
+            byte[] certData = Credentials.convertToPem(cert);
+            return keyStore.put(name, certData);
+        } catch (IOException e1) {
+            return false;
+        } catch (CertificateException e2) {
+            return false;
+        }
+    }
+
+    void removeKeys(android.security.KeyStore keyStore) {
+        String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
+        // a valid client certificate is configured
+        if (!TextUtils.isEmpty(client)) {
+            keyStore.delKey(Credentials.USER_PRIVATE_KEY + client);
+            keyStore.delete(Credentials.USER_CERTIFICATE + client);
+        }
+
+        String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
+        // a valid ca certificate is configured
+        if (!TextUtils.isEmpty(ca)) {
+            keyStore.delete(Credentials.CA_CERTIFICATE + ca);
+        }
+    }
+
+    /**
      * Set subject match. This is the substring to be matched against the subject of the
      * authentication server certificate.
      * @param subjectMatch substring to be matched
@@ -330,13 +543,28 @@
         return getFieldValue(SUBJECT_MATCH_KEY, "");
     }
 
+    /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
+    String getKeyId(WifiEnterpriseConfig current) {
+        String eap = mFields.get(EAP_KEY);
+        String phase2 = mFields.get(PHASE2_KEY);
+
+        // If either eap or phase2 are not initialized, use current config details
+        if (TextUtils.isEmpty((eap))) {
+            eap = current.mFields.get(EAP_KEY);
+        }
+        if (TextUtils.isEmpty(phase2)) {
+            phase2 = current.mFields.get(PHASE2_KEY);
+        }
+        return eap + "_" + phase2;
+    }
+
     /** Migrates the old style TLS config to the new config style. This should only be used
      * when restoring an old wpa_supplicant.conf or upgrading from a previous
      * platform version.
      * @return true if the config was updated
      * @hide
      */
-    public boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) {
+    boolean migrateOldEapTlsNative(WifiNative wifiNative, int netId) {
         String oldPrivateKey = wifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME);
         /*
          * If the old configuration value is not present, then there is nothing
@@ -395,6 +623,7 @@
      * @return the index into array
      */
     private int getStringIndex(String arr[], String toBeFound, int defaultIndex) {
+        if (TextUtils.isEmpty(toBeFound)) return defaultIndex;
         for (int i = 0; i < arr.length; i++) {
             if (toBeFound.equals(arr[i])) return i;
         }
@@ -408,7 +637,8 @@
      */
     private String getFieldValue(String key, String prefix) {
         String value = mFields.get(key);
-        if (EMPTY_VALUE.equals(value)) return "";
+        // Uninitialized or known to be empty after reading from supplicant
+        if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
         return removeDoubleQuotes(value).substring(prefix.length());
     }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 77604a4..1589fec 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -1332,10 +1332,19 @@
                                 P2pStateMachine.this, mGroup.getInterface());
                         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
                         WifiP2pDevice groupOwner = mGroup.getOwner();
-                        /* update group owner details with the ones found at discovery */
-                        groupOwner.updateSupplicantDetails(mPeers.get(groupOwner.deviceAddress));
-                        mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
-                        sendPeersChangedBroadcast();
+                        WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
+                        if (peer != null) {
+                            // update group owner details with peer details found at discovery
+                            groupOwner.updateSupplicantDetails(peer);
+                            mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
+                            sendPeersChangedBroadcast();
+                        } else {
+                            // A supplicant bug can lead to reporting an invalid
+                            // group owner address (all zeroes) at times. Avoid a
+                            // crash, but continue group creation since it is not
+                            // essential.
+                            logw("Unknown group owner " + groupOwner);
+                        }
                     }
                     transitionTo(mGroupCreatedState);
                     break;