Merge "Fixing various QuickSettings issues (Bug 7210343, Bug 7174839, Bug 7174738)" into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index ec930c4..df5429d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9746,6 +9746,7 @@
     ctor public Camera.CameraInfo();
     field public static final int CAMERA_FACING_BACK = 0; // 0x0
     field public static final int CAMERA_FACING_FRONT = 1; // 0x1
+    field public boolean canDisableShutterSound;
     field public int facing;
     field public int orientation;
   }
@@ -20079,6 +20080,40 @@
   public abstract class ScriptIntrinsic extends android.renderscript.Script {
   }
 
+  public class ScriptIntrinsicBlend extends android.renderscript.ScriptIntrinsic {
+    method public static android.renderscript.ScriptIntrinsicBlend create(android.renderscript.RenderScript, android.renderscript.Element);
+    method public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachClear(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachDst(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachDstAtop(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachDstIn(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachDstOut(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachDstOver(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachMultiply(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSrc(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSrcAtop(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSrcIn(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSrcOut(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSrcOver(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachSubtract(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public void forEachXor(android.renderscript.Allocation, android.renderscript.Allocation);
+    method public android.renderscript.Script.KernelID getKernelIDAdd();
+    method public android.renderscript.Script.KernelID getKernelIDClear();
+    method public android.renderscript.Script.KernelID getKernelIDDst();
+    method public android.renderscript.Script.KernelID getKernelIDDstAtop();
+    method public android.renderscript.Script.KernelID getKernelIDDstIn();
+    method public android.renderscript.Script.KernelID getKernelIDDstOut();
+    method public android.renderscript.Script.KernelID getKernelIDDstOver();
+    method public android.renderscript.Script.KernelID getKernelIDMultiply();
+    method public android.renderscript.Script.KernelID getKernelIDSrc();
+    method public android.renderscript.Script.KernelID getKernelIDSrcAtop();
+    method public android.renderscript.Script.KernelID getKernelIDSrcIn();
+    method public android.renderscript.Script.KernelID getKernelIDSrcOut();
+    method public android.renderscript.Script.KernelID getKernelIDSrcOver();
+    method public android.renderscript.Script.KernelID getKernelIDSubtract();
+    method public android.renderscript.Script.KernelID getKernelIDXor();
+  }
+
   public final class ScriptIntrinsicBlur extends android.renderscript.ScriptIntrinsic {
     method public static android.renderscript.ScriptIntrinsicBlur create(android.renderscript.RenderScript, android.renderscript.Element);
     method public void forEach(android.renderscript.Allocation);
@@ -28970,7 +29005,6 @@
     method public int describeContents();
     method public int getLayoutId();
     method public java.lang.String getPackage();
-    method public void mergeRemoteViews(android.widget.RemoteViews);
     method public boolean onLoadClass(java.lang.Class);
     method public void reapply(android.content.Context, android.view.View);
     method public void removeAllViews(int);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7870031..18503f6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,10 +42,8 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.ManifestDigest;
-import android.content.pm.UserInfo;
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -453,11 +451,17 @@
 
     @Override
     public ResolveInfo resolveActivity(Intent intent, int flags) {
+        return resolveActivityAsUser(intent, flags, UserHandle.myUserId());
+    }
+
+    @Override
+    public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
         try {
             return mPM.resolveIntent(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                    flags, UserHandle.myUserId());
+                flags,
+                userId);
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -466,12 +470,12 @@
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
                                                    int flags) {
-        return queryIntentActivitiesForUser(intent, flags, UserHandle.myUserId());
+        return queryIntentActivitiesAsUser(intent, flags, UserHandle.myUserId());
     }
 
     /** @hide Same as above but for a specific user */
     @Override
-    public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+    public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                                                    int flags, int userId) {
         try {
             return mPM.queryIntentActivities(
@@ -551,19 +555,24 @@
     }
 
     @Override
-    public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
+    public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
         try {
             return mPM.queryIntentServices(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserHandle.myUserId());
+                userId);
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
     }
 
     @Override
+    public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
+        return queryIntentServicesAsUser(intent, flags, UserHandle.myUserId());
+    }
+
+    @Override
     public ProviderInfo resolveContentProvider(String name,
                                                int flags) {
         try {
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index c86826f..f258f17 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -226,7 +226,12 @@
 
         if (jail == null) jail = new ParcelableSparseArray();
 
-        super.dispatchRestoreInstanceState(jail);
+        try  {
+            super.dispatchRestoreInstanceState(jail);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to restoreInstanceState for widget id: " + mAppWidgetId + ", "
+                    + (mInfo == null ? "null" : mInfo.provider), e);
+        }
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fd488ae..59b057a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -835,6 +835,15 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device has at least one camera pointing in
+     * some direction.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device's camera supports flash.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1797,6 +1806,39 @@
     public abstract ResolveInfo resolveActivity(Intent intent, int flags);
 
     /**
+     * Determine the best action to perform for a given Intent for a given user. This
+     * is how {@link Intent#resolveActivity} finds an activity if a class has not
+     * been explicitly specified.
+     *
+     * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
+     * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
+     * only flag.  You need to do so to resolve the activity in the same way
+     * that {@link android.content.Context#startActivity(Intent)} and
+     * {@link android.content.Intent#resolveActivity(PackageManager)
+     * Intent.resolveActivity(PackageManager)} do.</p>
+     *
+     * @param intent An intent containing all of the desired specification
+     *               (action, data, type, category, and/or component).
+     * @param flags Additional option flags.  The most important is
+     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
+     * @param userId The user id.
+     *
+     * @return Returns a ResolveInfo containing the final activity intent that
+     *         was determined to be the best action.  Returns null if no
+     *         matching activity was found. If multiple matching activities are
+     *         found and there is no default set, returns a ResolveInfo
+     *         containing something else, such as the activity resolver.
+     *
+     * @see #MATCH_DEFAULT_ONLY
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_RESOLVED_FILTER
+     *
+     * @hide
+     */
+    public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+
+    /**
      * Retrieve all activities that can be performed for the given intent.
      *
      * @param intent The desired intent as per resolveActivity().
@@ -1836,7 +1878,7 @@
      * @see #GET_RESOLVED_FILTER
      * @hide
      */
-    public abstract List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+    public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
             int flags, int userId);
 
 
@@ -1944,6 +1986,27 @@
             int flags);
 
     /**
+     * Retrieve all services that can match the given intent for a given user.
+     *
+     * @param intent The desired intent as per resolveService().
+     * @param flags Additional option flags.
+     * @param userId The user id.
+     *
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
+     *         ServiceInfo. These are ordered from best to worst match -- that
+     *         is, the first item in the list is what is returned by
+     *         resolveService().  If there are no matching services, an empty
+     *         list is returned.
+     *
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_RESOLVED_FILTER
+     *
+     * @hide
+     */
+    public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
+            int flags, int userId);
+
+    /**
      * Find a single content provider by its base path name.
      *
      * @param name The name of the provider to find.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 7b3a8af..375d788 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -233,6 +233,21 @@
          * @see Parameters#setJpegThumbnailSize(int, int)
          */
         public int orientation;
+
+        /**
+         * <p>Whether the shutter sound can be disabled.</p>
+         *
+         * <p>On some devices, the camera shutter sound cannot be turned off
+         * through {@link #enableShutterSound enableShutterSound}. This field
+         * can be used to determine whether a call to disable the shutter sound
+         * will succeed.</p>
+         *
+         * <p>If this field is set to true, then a call of
+         * {@code enableShutterSound(false)} will be successful. If set to
+         * false, then that call will fail, and the shutter sound will be played
+         * when {@link Camera#takePicture takePicture} is called.</p>
+         */
+        public boolean canDisableShutterSound;
     };
 
     /**
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e0e8de3..bafab21 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -149,6 +149,17 @@
             "debug.hwui.show_layers_updates";
 
     /**
+     * Turn on to show overdraw level.
+     *
+     * Possible values:
+     * "true", to enable overdraw debugging
+     * "false", to disable overdraw debugging
+     *
+     * @hide
+     */
+    public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw";
+
+    /**
      * A process can set this flag to false to prevent the use of hardware
      * rendering.
      * 
@@ -649,6 +660,7 @@
         int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
         
         final boolean mDebugDirtyRegions;
+        final boolean mShowOverdraw;
 
         final int mGlVersion;
         final boolean mTranslucent;
@@ -698,6 +710,9 @@
             if (mDebugDirtyRegions) {
                 Log.d(LOG_TAG, "Debugging dirty regions");
             }
+
+            mShowOverdraw = SystemProperties.getBoolean(
+                    HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false);
         }
 
         @Override
@@ -1414,7 +1429,8 @@
                     EGL_BLUE_SIZE, 8,
                     EGL_ALPHA_SIZE, 8,
                     EGL_DEPTH_SIZE, 0,
-                    EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
+                    // TODO: Find a better way to choose the stencil size
+                    EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0,
                     EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
                             (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
                     EGL_NONE
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 77fd12a..732699b 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -27,6 +27,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.IWindow;
 import android.view.View;
@@ -79,6 +80,8 @@
 
     final IAccessibilityManager mService;
 
+    final int mUserId;
+
     final Handler mHandler;
 
     boolean mIsEnabled;
@@ -129,35 +132,72 @@
     }
 
     /**
+     * Creates the singleton AccessibilityManager to be shared across users. This
+     * has to be called before the local AccessibilityManager is created to ensure
+     * it registers itself in the system correctly.
+     * <p>
+     * Note: Calling this method requires INTERACT_ACROSS_USERS_FULL or
+     *       INTERACT_ACROSS_USERS permission.
+     * </p>
+     * @param context Context in which this manager operates.
+     * @throws IllegalStateException if not called before the local
+     *     AccessibilityManager is instantiated.
+     *
+     * @hide
+     */
+    public static void createAsSharedAcrossUsers(Context context) {
+        synchronized (sInstanceSync) {
+            if (sInstance != null) {
+                throw new IllegalStateException("AccessibilityManager already created.");
+            }
+            createSingletonInstance(context, UserHandle.USER_CURRENT);
+        }
+    }
+
+    /**
      * Get an AccessibilityManager instance (create one if necessary).
      *
+     * @param context Context in which this manager operates.
+     *
      * @hide
      */
     public static AccessibilityManager getInstance(Context context) {
         synchronized (sInstanceSync) {
             if (sInstance == null) {
-                IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-                IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
-                sInstance = new AccessibilityManager(context, service);
+                createSingletonInstance(context, UserHandle.myUserId());
             }
         }
         return sInstance;
     }
 
     /**
+     * Creates the singleton instance.
+     *
+     * @param context Context in which this manager operates.
+     * @param userId The user id under which to operate.
+     */
+    private static void createSingletonInstance(Context context, int userId) {
+        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+        IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+        sInstance = new AccessibilityManager(context, service, userId);
+    }
+
+    /**
      * Create an instance.
      *
      * @param context A {@link Context}.
      * @param service An interface to the backing service.
+     * @param userId User id under which to run.
      *
      * @hide
      */
-    public AccessibilityManager(Context context, IAccessibilityManager service) {
+    public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
         mHandler = new MyHandler(context.getMainLooper());
         mService = service;
+        mUserId = userId;
 
         try {
-            final int stateFlags = mService.addClient(mClient);
+            final int stateFlags = mService.addClient(mClient, userId);
             setState(stateFlags);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -222,7 +262,7 @@
             // client using it is called through Binder from another process. Example: MMS
             // app adds a SMS notification and the NotificationManagerService calls this method
             long identityToken = Binder.clearCallingIdentity();
-            doRecycle = mService.sendAccessibilityEvent(event);
+            doRecycle = mService.sendAccessibilityEvent(event, mUserId);
             Binder.restoreCallingIdentity(identityToken);
             if (DEBUG) {
                 Log.i(LOG_TAG, event + " sent");
@@ -244,7 +284,7 @@
             throw new IllegalStateException("Accessibility off. Did you forget to check that?");
         }
         try {
-            mService.interrupt();
+            mService.interrupt(mUserId);
             if (DEBUG) {
                 Log.i(LOG_TAG, "Requested interrupt from all services");
             }
@@ -280,7 +320,7 @@
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getInstalledAccessibilityServiceList();
+            services = mService.getInstalledAccessibilityServiceList(mUserId);
             if (DEBUG) {
                 Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
             }
@@ -307,7 +347,7 @@
             int feedbackTypeFlags) {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags);
+            services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId);
             if (DEBUG) {
                 Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
             }
@@ -385,7 +425,7 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection) {
         try {
-            return mService.addAccessibilityInteractionConnection(windowToken, connection);
+            return mService.addAccessibilityInteractionConnection(windowToken, connection, mUserId);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
         }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 5b5134a..60238627 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -34,18 +34,18 @@
  */
 interface IAccessibilityManager {
 
-    int addClient(IAccessibilityManagerClient client);
+    int addClient(IAccessibilityManagerClient client, int userId);
 
-    boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent);
+    boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
 
-    List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
+    List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
-    List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType);
+    List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
 
-    void interrupt();
+    void interrupt(int userId);
 
     int addAccessibilityInteractionConnection(IWindow windowToken,
-        in IAccessibilityInteractionConnection connection);
+        in IAccessibilityInteractionConnection connection, int userId);
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index d23f52c..1c47615 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -4594,11 +4594,11 @@
     private void ensureSelectionHandles() {
         if (mSelectHandleCenter == null) {
             mSelectHandleCenter = mContext.getResources().getDrawable(
-                    com.android.internal.R.drawable.text_select_handle_middle);
+                    com.android.internal.R.drawable.text_select_handle_middle).mutate();
             mSelectHandleLeft = mContext.getResources().getDrawable(
-                    com.android.internal.R.drawable.text_select_handle_left);
+                    com.android.internal.R.drawable.text_select_handle_left).mutate();
             mSelectHandleRight = mContext.getResources().getDrawable(
-                    com.android.internal.R.drawable.text_select_handle_right);
+                    com.android.internal.R.drawable.text_select_handle_right).mutate();
             // All handles have the same height, so we can save effort with
             // this assumption.
             mSelectOffset = new Point(0,
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index fe6c4f5..736566e4 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.database.DataSetObservable;
-import android.database.DataSetObserver;
 import android.os.AsyncTask;
 import android.text.TextUtils;
 import android.util.Log;
@@ -458,13 +457,18 @@
      * </p>
      *
      * @return An {@link Intent} for launching the activity or null if the
-     *         policy has consumed the intent.
+     *         policy has consumed the intent or there is not current intent
+     *         set via {@link #setIntent(Intent)}.
      *
      * @see HistoricalRecord
      * @see OnChooseActivityListener
      */
     public Intent chooseActivity(int index) {
         synchronized (mInstanceLock) {
+            if (mIntent == null) {
+                return null;
+            }
+
             ensureConsistentState();
 
             ActivityResolveInfo chosenActivity = mActivities.get(index);
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 27d15f6..06dadb0 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -257,7 +257,7 @@
         try {
             pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
         } catch (NameNotFoundException e) {
-            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
+            Log.w(TAG, "Couldn't retrieve permissions for package:"+packageName);
             return;
         }
         // Extract all user permissions
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index b06da06..6ddfc3b 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -1609,7 +1609,7 @@
         }
 
         /**
-         * Initialize the paint isntances.
+         * Initialize the paint instances.
          */
         private void initilaizePaints() {
             mDrawPaint.setFakeBoldText(false);
@@ -1620,6 +1620,7 @@
             mMonthNumDrawPaint.setAntiAlias(true);
             mMonthNumDrawPaint.setStyle(Style.FILL);
             mMonthNumDrawPaint.setTextAlign(Align.CENTER);
+            mMonthNumDrawPaint.setTextSize(mDateTextSize);
         }
 
         /**
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 87ef23f..1a47ce2 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -222,6 +222,14 @@
         int viewId;
     }
 
+    /**
+     * Merges the passed RemoteViews actions with this RemoteViews actions according to
+     * action-specific merge rules.
+     * 
+     * @param newRv
+     * 
+     * @hide
+     */
     public void mergeRemoteViews(RemoteViews newRv) {
         // We first copy the new RemoteViews, as the process of merging modifies the way the actions
         // reference the bitmap cache. We don't want to modify the object as it may need to
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f3bef08..09457cc 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -215,36 +215,26 @@
     }
 
     public void setCurrentUser(int userId) {
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            mCurrentUserId = userId;
-        } else {
-            throw new SecurityException("Only the system process can set the current user");
-        }
+        mCurrentUserId = userId;
     }
 
     public int getCurrentUser() {
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            if (mCurrentUserId != UserHandle.USER_NULL) {
-                // Someone is regularly updating using setCurrentUser() use that value.
-                return mCurrentUserId;
-            }
-            try {
-                return ActivityManagerNative.getDefault().getCurrentUser().id;
-            } catch (RemoteException re) {
-                return UserHandle.USER_OWNER;
-            }
-        } else {
-            throw new SecurityException("Only the system process can get the current user");
+        if (mCurrentUserId != UserHandle.USER_NULL) {
+            // Someone is regularly updating using setCurrentUser() use that value.
+            return mCurrentUserId;
+        }
+        try {
+            return ActivityManagerNative.getDefault().getCurrentUser().id;
+        } catch (RemoteException re) {
+            return UserHandle.USER_OWNER;
         }
     }
 
     public void removeUser(int userId) {
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            try {
-                getLockSettings().removeUser(userId);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Couldn't remove lock settings for user " + userId);
-            }
+        try {
+            getLockSettings().removeUser(userId);
+        } catch (RemoteException re) {
+            Log.e(TAG, "Couldn't remove lock settings for user " + userId);
         }
     }
 
@@ -591,10 +581,6 @@
         // Compute the hash
         final byte[] hash = passwordToHash(password);
         try {
-            if (Process.myUid() != Process.SYSTEM_UID && userHandle != UserHandle.myUserId()) {
-                throw new SecurityException(
-                        "Only the system process can save lock password for another user");
-            }
             getLockSettings().setLockPassword(hash, userHandle);
             DevicePolicyManager dpm = getDevicePolicyManager();
             KeyStore keyStore = KeyStore.getInstance();
@@ -1007,8 +993,8 @@
      *   or null if there is no next alarm.
      */
     public String getNextAlarm() {
-        String nextAlarm = Settings.System.getString(mContentResolver,
-                Settings.System.NEXT_ALARM_FORMATTED);
+        String nextAlarm = Settings.System.getStringForUser(mContentResolver,
+                Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT);
         if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
             return null;
         }
@@ -1035,8 +1021,9 @@
 
     public int[] getUserDefinedWidgets() {
         int appWidgetId = -1;
-        String appWidgetIdString = Settings.Secure.getString(
-                mContentResolver, Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID);
+        String appWidgetIdString = Settings.Secure.getStringForUser(
+                mContentResolver, Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID,
+                UserHandle.USER_CURRENT);
         if (appWidgetIdString != null) {
             appWidgetId = (int) Integer.decode(appWidgetIdString);
         }
@@ -1046,8 +1033,9 @@
 
     public int getStatusWidget() {
         int appWidgetId = -1;
-        String appWidgetIdString = Settings.Secure.getString(
-                mContentResolver, Settings.Secure.LOCK_SCREEN_STATUS_APPWIDGET_ID);
+        String appWidgetIdString = Settings.Secure.getStringForUser(
+                mContentResolver, Settings.Secure.LOCK_SCREEN_STATUS_APPWIDGET_ID,
+                UserHandle.USER_CURRENT);
         if (appWidgetIdString != null) {
             appWidgetId = (int) Integer.decode(appWidgetIdString);
         }
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index e1e97a1..99d49ec 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -23,6 +23,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 
+#include <cutils/properties.h>
 #include <utils/Vector.h>
 
 #include <gui/SurfaceTexture.h>
@@ -38,6 +39,7 @@
     jfieldID    surfaceTexture;
     jfieldID    facing;
     jfieldID    orientation;
+    jfieldID    canDisableShutterSound;
     jfieldID    face_rect;
     jfieldID    face_score;
     jfieldID    rect_left;
@@ -453,6 +455,12 @@
     }
     env->SetIntField(info_obj, fields.facing, cameraInfo.facing);
     env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation);
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.camera.sound.forced", value, "0");
+    jboolean canDisableShutterSound = (strncmp(value, "0", 2) == 0);
+    env->SetBooleanField(info_obj, fields.canDisableShutterSound,
+            canDisableShutterSound);
 }
 
 // connect to camera service
@@ -962,6 +970,8 @@
           ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture },
         { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
         { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
+        { "android/hardware/Camera$CameraInfo", "canDisableShutterSound",   "Z",
+          &fields.canDisableShutterSound },
         { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect },
         { "android/hardware/Camera$Face", "score", "I", &fields.face_score },
         { "android/graphics/Rect", "left", "I", &fields.rect_left },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 661b70c..a8bee4d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -45,6 +45,7 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
diff --git a/docs/html/guide/topics/ui/controls.jd b/docs/html/guide/topics/ui/controls.jd
index 83bb0c8..a58d9f9 100644
--- a/docs/html/guide/topics/ui/controls.jd
+++ b/docs/html/guide/topics/ui/controls.jd
@@ -15,7 +15,7 @@
 href="{@docRoot}guide/topics/ui/declaring-layout.html">XML layout</a>. For example, here's a
 layout with a text field and button:</p>
 
-<pre>
+<pre style="clear:right">
 &lt;?xml version="1.0" encoding="utf-8"?>
 &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
new file mode 100644
index 0000000..13c03af
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+/**
+ * Intrinsic kernels for blending two buffers. Each blend function is a separate
+ * kernel to make it easy to change between blend modes.
+ **/
+public class ScriptIntrinsicBlend extends ScriptIntrinsic {
+    ScriptIntrinsicBlend(int id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are uchar4
+     *
+     *
+     * @param rs
+     * @param e
+     *
+     * @return ScriptIntrinsicBlend
+     */
+    public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
+        int id = rs.nScriptIntrinsicCreate(6, e.getID(rs));
+        return new ScriptIntrinsicBlend(id, rs);
+
+    }
+
+    private void blend(int id, Allocation ain, Allocation aout) {
+        if (ain.getElement() != Element.U8_4(mRS)) {
+            throw new RSIllegalArgumentException("Input not of expected format.");
+        }
+        if (aout.getElement() != Element.U8_4(mRS)) {
+            throw new RSIllegalArgumentException("Output not of expected format.");
+        }
+        forEach(id, ain, aout, null);
+    }
+
+    /**
+     * dst = {0, 0, 0, 0}
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachClear(Allocation ain, Allocation aout) {
+        blend(0, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Clear kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDClear() {
+        return createKernelID(0, 3, null, null);
+    }
+
+
+    /**
+     * dst = src
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrc(Allocation ain, Allocation aout) {
+        blend(1, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Src kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrc() {
+        return createKernelID(1, 3, null, null);
+    }
+
+    /**
+     * dst = dst
+     * This is a NOP
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDst(Allocation ain, Allocation aout) {
+        // NOP
+    }
+
+    /**
+     * Get a KernelID for the Dst kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDst() {
+        return createKernelID(2, 3, null, null);
+    }
+
+    /**
+     * dst = src + dst * (1.0 - src.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcOver(Allocation ain, Allocation aout) {
+        blend(3, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcOver kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcOver() {
+        return createKernelID(3, 3, null, null);
+    }
+
+    /**
+     * dst = dst + src * (1.0 - dst.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstOver(Allocation ain, Allocation aout) {
+        blend(4, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstOver kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstOver() {
+        return createKernelID(4, 3, null, null);
+    }
+
+    /**
+     * dst = src * dst.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcIn(Allocation ain, Allocation aout) {
+        blend(5, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcIn kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcIn() {
+        return createKernelID(5, 3, null, null);
+    }
+
+    /**
+     * dst = dst * src.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstIn(Allocation ain, Allocation aout) {
+        blend(6, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstIn kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstIn() {
+        return createKernelID(6, 3, null, null);
+    }
+
+    /**
+     * dst = src * (1.0 - dst.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcOut(Allocation ain, Allocation aout) {
+        blend(7, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcOut kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcOut() {
+        return createKernelID(7, 3, null, null);
+    }
+
+    /**
+     * dst = dst * (1.0 - src.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstOut(Allocation ain, Allocation aout) {
+        blend(8, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstOut kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstOut() {
+        return createKernelID(8, 3, null, null);
+    }
+
+    /**
+     * dst.rgb = src.rgb * dst.a + (1.0 - src.a) * dst.rgb
+     * dst.a = dst.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcAtop(Allocation ain, Allocation aout) {
+        blend(9, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcAtop kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcAtop() {
+        return createKernelID(9, 3, null, null);
+    }
+
+    /**
+     * dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
+     * dst.a = src.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstAtop(Allocation ain, Allocation aout) {
+        blend(10, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstAtop kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstAtop() {
+        return createKernelID(10, 3, null, null);
+    }
+
+    /**
+     * dst = {src.r ^ dst.r, src.g ^ dst.g, src.b ^ dst.b, src.a ^ dst.a}
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachXor(Allocation ain, Allocation aout) {
+        blend(11, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Xor kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDXor() {
+        return createKernelID(11, 3, null, null);
+    }
+
+    ////////
+/*
+    public void forEachNormal(Allocation ain, Allocation aout) {
+        blend(12, ain, aout);
+    }
+
+    public void forEachAverage(Allocation ain, Allocation aout) {
+        blend(13, ain, aout);
+    }
+*/
+    /**
+     * dst = src * dst
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachMultiply(Allocation ain, Allocation aout) {
+        blend(14, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Multiply kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDMultiply() {
+        return createKernelID(14, 3, null, null);
+    }
+
+/*
+    public void forEachScreen(Allocation ain, Allocation aout) {
+        blend(15, ain, aout);
+    }
+
+    public void forEachDarken(Allocation ain, Allocation aout) {
+        blend(16, ain, aout);
+    }
+
+    public void forEachLighten(Allocation ain, Allocation aout) {
+        blend(17, ain, aout);
+    }
+
+    public void forEachOverlay(Allocation ain, Allocation aout) {
+        blend(18, ain, aout);
+    }
+
+    public void forEachHardlight(Allocation ain, Allocation aout) {
+        blend(19, ain, aout);
+    }
+
+    public void forEachSoftlight(Allocation ain, Allocation aout) {
+        blend(20, ain, aout);
+    }
+
+    public void forEachDifference(Allocation ain, Allocation aout) {
+        blend(21, ain, aout);
+    }
+
+    public void forEachNegation(Allocation ain, Allocation aout) {
+        blend(22, ain, aout);
+    }
+
+    public void forEachExclusion(Allocation ain, Allocation aout) {
+        blend(23, ain, aout);
+    }
+
+    public void forEachColorDodge(Allocation ain, Allocation aout) {
+        blend(24, ain, aout);
+    }
+
+    public void forEachInverseColorDodge(Allocation ain, Allocation aout) {
+        blend(25, ain, aout);
+    }
+
+    public void forEachSoftDodge(Allocation ain, Allocation aout) {
+        blend(26, ain, aout);
+    }
+
+    public void forEachColorBurn(Allocation ain, Allocation aout) {
+        blend(27, ain, aout);
+    }
+
+    public void forEachInverseColorBurn(Allocation ain, Allocation aout) {
+        blend(28, ain, aout);
+    }
+
+    public void forEachSoftBurn(Allocation ain, Allocation aout) {
+        blend(29, ain, aout);
+    }
+
+    public void forEachReflect(Allocation ain, Allocation aout) {
+        blend(30, ain, aout);
+    }
+
+    public void forEachGlow(Allocation ain, Allocation aout) {
+        blend(31, ain, aout);
+    }
+
+    public void forEachFreeze(Allocation ain, Allocation aout) {
+        blend(32, ain, aout);
+    }
+
+    public void forEachHeat(Allocation ain, Allocation aout) {
+        blend(33, ain, aout);
+    }
+*/
+    /**
+     * dst = min(src + dst, 1.0)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachAdd(Allocation ain, Allocation aout) {
+        blend(34, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Add kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDAdd() {
+        return createKernelID(34, 3, null, null);
+    }
+
+    /**
+     * dst = max(dst - src, 0.0)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSubtract(Allocation ain, Allocation aout) {
+        blend(35, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Subtract kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSubtract() {
+        return createKernelID(35, 3, null, null);
+    }
+
+/*
+    public void forEachStamp(Allocation ain, Allocation aout) {
+        blend(36, ain, aout);
+    }
+
+    public void forEachRed(Allocation ain, Allocation aout) {
+        blend(37, ain, aout);
+    }
+
+    public void forEachGreen(Allocation ain, Allocation aout) {
+        blend(38, ain, aout);
+    }
+
+    public void forEachBlue(Allocation ain, Allocation aout) {
+        blend(39, ain, aout);
+    }
+
+    public void forEachHue(Allocation ain, Allocation aout) {
+        blend(40, ain, aout);
+    }
+
+    public void forEachSaturation(Allocation ain, Allocation aout) {
+        blend(41, ain, aout);
+    }
+
+    public void forEachColor(Allocation ain, Allocation aout) {
+        blend(42, ain, aout);
+    }
+
+    public void forEachLuminosity(Allocation ain, Allocation aout) {
+        blend(43, ain, aout);
+    }
+*/
+}
+
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 068eb9e..22f1dec 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -131,6 +131,13 @@
     } else {
         debugLayersUpdates = false;
     }
+
+    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
+        INIT_LOGD("  Overdraw debug enabled: %s", property);
+        debugOverdraw = !strcmp(property, "true");
+    } else {
+        debugOverdraw = false;
+    }
 }
 
 void Caches::terminate() {
@@ -429,7 +436,9 @@
 
 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) {
     if (extensions.hasTiledRendering()) {
-        glStartTilingQCOM(x, y, width, height, opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM);
+        glStartTilingQCOM(x, y, width, height,
+                (opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM) |
+                (debugOverdraw ? GL_STENCIL_BUFFER_BIT0_QCOM : 0));
     }
 }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 50e9e758..48efd10 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -242,6 +242,7 @@
     // Misc
     GLint maxTextureSize;
     bool debugLayersUpdates;
+    bool debugOverdraw;
 
     TextureCache textureCache;
     LayerCache layerCache;
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 5817977..e80b325 100755
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -76,8 +76,10 @@
 
     bindDitherTexture();
 
+    float ditherSize = 1.0f / DITHER_KERNEL_SIZE;
     glUniform1i(program->getUniform("ditherSampler"), textureSlot);
-    glUniform1f(program->getUniform("ditherSize"), 1.0f / DITHER_KERNEL_SIZE);
+    glUniform1f(program->getUniform("ditherSize"), ditherSize);
+    glUniform1f(program->getUniform("ditherSizeSquared"), ditherSize * ditherSize);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index bdf1229b..a4403c8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -194,6 +194,8 @@
     mTilingSnapshot = mSnapshot;
     startTiling(mTilingSnapshot, true);
 
+    debugOverdraw(true, true);
+
     if (!opaque) {
         mCaches.enableScissor();
         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
@@ -231,6 +233,7 @@
 }
 
 void OpenGLRenderer::finish() {
+    renderOverdraw();
     endTiling();
 
     if (!suppressErrorChecks()) {
@@ -265,6 +268,40 @@
     }
 }
 
+void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
+    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+        if (clear) {
+            mCaches.disableScissor();
+            mCaches.stencil.clear();
+        }
+        if (enable) {
+            mCaches.stencil.enableDebugWrite();
+        } else {
+            mCaches.stencil.disable();
+        }
+    }
+}
+
+void OpenGLRenderer::renderOverdraw() {
+    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+        const Rect* clip = mTilingSnapshot->clipRect;
+
+        mCaches.enableScissor();
+        mCaches.setScissor(clip->left, mTilingSnapshot->height - clip->bottom,
+                clip->right - clip->left, clip->bottom - clip->top);
+
+        mCaches.stencil.enableDebugTest(2);
+        drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(3);
+        drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(4);
+        drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(4, true);
+        drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.disable();
+    }
+}
+
 void OpenGLRenderer::interrupt() {
     if (mCaches.currentProgram) {
         if (mCaches.currentProgram->isInUse()) {
@@ -276,12 +313,14 @@
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
     mCaches.disbaleTexCoordsVertexArray();
+    debugOverdraw(false, false);
 }
 
 void OpenGLRenderer::resume() {
     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    debugOverdraw(true, false);
 
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
@@ -302,6 +341,7 @@
     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    debugOverdraw(true, false);
 
     mCaches.resetScissor();
     dirtyClip();
@@ -407,7 +447,10 @@
         OpenGLRenderer* renderer = layer->renderer;
         Rect& dirty = layer->dirtyRect;
 
-        if (inFrame) endTiling();
+        if (inFrame) {
+            endTiling();
+            debugOverdraw(false, false);
+        }
 
         renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
         renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
@@ -724,6 +767,7 @@
     mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     endTiling();
+    debugOverdraw(false, false);
     // Bind texture to FBO
     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
     layer->bindTexture();
@@ -772,6 +816,7 @@
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
         // Unbind current FBO and restore previous one
         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+        debugOverdraw(true, false);
 
         startTiling(previous);
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7d5da68..46e66cb 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -723,6 +723,9 @@
      */
     void drawRegionRects(const Region& region);
 
+    void debugOverdraw(bool enable, bool clear);
+    void renderOverdraw();
+
     /**
      * Should be invoked every time the glScissor is modified.
      */
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index de7afed..c81319e 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -53,11 +53,14 @@
         "uniform mediump float pointSize;\n";
 const char* gVS_Header_Uniforms_HasGradient[3] = {
         // Linear
-        "uniform mat4 screenSpace;\n",
+        "uniform mat4 screenSpace;\n"
+        "uniform float ditherSize;\n",
         // Circular
-        "uniform mat4 screenSpace;\n",
+        "uniform mat4 screenSpace;\n"
+        "uniform float ditherSize;\n",
         // Sweep
         "uniform mat4 screenSpace;\n"
+        "uniform float ditherSize;\n"
 };
 const char* gVS_Header_Uniforms_HasBitmap =
         "uniform mat4 textureTransform;\n"
@@ -75,16 +78,22 @@
         "varying highp vec2 outPointBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_HasGradient[6] = {
         // Linear
-        "varying highp vec2 linear;\n",
-        "varying float linear;\n",
+        "varying highp vec2 linear;\n"
+        "varying vec2 ditherTexCoords;\n",
+        "varying float linear;\n"
+        "varying vec2 ditherTexCoords;\n",
 
         // Circular
-        "varying highp vec2 circular;\n",
-        "varying highp vec2 circular;\n",
+        "varying highp vec2 circular;\n"
+        "varying vec2 ditherTexCoords;\n",
+        "varying highp vec2 circular;\n"
+        "varying vec2 ditherTexCoords;\n",
 
         // Sweep
-        "varying highp vec2 sweep;\n",
-        "varying highp vec2 sweep;\n",
+        "varying highp vec2 sweep;\n"
+        "varying vec2 ditherTexCoords;\n",
+        "varying highp vec2 sweep;\n"
+        "varying vec2 ditherTexCoords;\n",
 };
 const char* gVS_Main =
         "\nvoid main(void) {\n";
@@ -94,16 +103,22 @@
         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
 const char* gVS_Main_OutGradient[6] = {
         // Linear
-        "    linear = vec2((screenSpace * position).x, 0.5);\n",
-        "    linear = (screenSpace * position).x;\n",
+        "    linear = vec2((screenSpace * position).x, 0.5);\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    linear = (screenSpace * position).x;\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
 
         // Circular
-        "    circular = (screenSpace * position).xy;\n",
-        "    circular = (screenSpace * position).xy;\n",
+        "    circular = (screenSpace * position).xy;\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    circular = (screenSpace * position).xy;\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
 
         // Sweep
-        "    sweep = (screenSpace * position).xy;\n",
-        "    sweep = (screenSpace * position).xy;\n",
+        "    sweep = (screenSpace * position).xy;\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    sweep = (screenSpace * position).xy;\n"
+        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
@@ -144,7 +159,7 @@
 const char* gFS_Uniforms_ExternalTextureSampler =
         "uniform samplerExternalOES baseSampler;\n";
 #define FS_UNIFORMS_DITHER \
-        "uniform float ditherSize;\n" \
+        "uniform float ditherSizeSquared;\n" \
         "uniform sampler2D ditherSampler;\n"
 #define FS_UNIFORMS_GRADIENT \
         "uniform vec4 startColor;\n" \
@@ -188,7 +203,7 @@
         "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
 
 #define FS_MAIN_DITHER \
-        "texture2D(ditherSampler, gl_FragCoord.xy * ditherSize).a * ditherSize * ditherSize"
+        "texture2D(ditherSampler, ditherTexCoords).a * ditherSizeSquared"
 const char* gFS_Main_AddDitherToGradient =
         "    gradientColor += " FS_MAIN_DITHER ";\n";
 
@@ -511,9 +526,6 @@
                 shader.append(gVS_Main_AALine);
             }
         }
-        if (description.hasGradient) {
-            shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
-        }
         if (description.hasBitmap) {
             shader.append(description.isPoint ?
                     gVS_Main_OutPointBitmapTexCoords :
@@ -524,6 +536,9 @@
         }
         // Output transformed position
         shader.append(gVS_Main_Position);
+        if (description.hasGradient) {
+            shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
+        }
     }
     // End the shader
     shader.append(gVS_Footer);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 0e3268e..31e60e44 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -37,7 +37,7 @@
 // Defines the size in bits of the stencil buffer
 // Note: Only 1 bit is required for clipping but more bits are required
 // to properly implement the winding fill rule when rasterizing paths
-#define STENCIL_BUFFER_SIZE 0
+#define STENCIL_BUFFER_SIZE 8
 
 /**
  * Debug level for app developers. The value is a numeric value defined
@@ -56,11 +56,17 @@
 };
 
 /**
- * Used to enable/disbale layers update debugging. The accepted values are
+ * Used to enable/disable layers update debugging. The accepted values are
  * "true" and "false". The default value is "false".
  */
 #define PROPERTY_DEBUG_LAYERS_UPDATES "debug.hwui.show_layers_updates"
 
+/**
+ * Used to enable/disable overdraw debugging. The accepted values are
+ * "true" and "false". The default value is "false".
+ */
+#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.show_overdraw"
+
 // 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"
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp
index 7dfdf0e..84df82b 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/Stencil.cpp
@@ -37,7 +37,7 @@
 void Stencil::enableTest() {
     if (mState != kTest) {
         enable();
-        glStencilFunc(GL_EQUAL, 0x0, 0x1);
+        glStencilFunc(GL_EQUAL, 0x1, 0x1);
         // We only want to test, let's keep everything
         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -56,8 +56,27 @@
     }
 }
 
+void Stencil::enableDebugTest(GLint value, bool greater) {
+    enable();
+    glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
+    // We only want to test, let's keep everything
+    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+    mState = kTest;
+}
+
+void Stencil::enableDebugWrite() {
+    if (mState != kWrite) {
+        enable();
+        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
+        // The test always passes so the first two values are meaningless
+        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        mState = kWrite;
+    }
+}
+
 void Stencil::enable() {
-    if (!mState == kDisabled) {
+    if (mState == kDisabled) {
         glEnable(GL_STENCIL_TEST);
     }
 }
diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h
index 67ccc78..2f8a66a 100644
--- a/libs/hwui/Stencil.h
+++ b/libs/hwui/Stencil.h
@@ -59,6 +59,16 @@
     void enableWrite();
 
     /**
+     * The test passes only when equal to the specified value.
+     */
+    void enableDebugTest(GLint value, bool greater = false);
+
+    /**
+     * Used for debugging. The stencil test always passes and increments.
+     */
+    void enableDebugWrite();
+
+    /**
      * Disables stencil test and write.
      */
     void disable();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1bde949..427fe91 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -32,6 +32,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
 
 public class SystemUIService extends Service {
     static final String TAG = "SystemUIService";
@@ -67,6 +68,10 @@
 
     @Override
     public void onCreate() {
+        // Tell the accessibility layer that this process will
+        // run as the current user, i.e. run across users.
+        AccessibilityManager.createAsSharedAcrossUsers(this);
+
         // Pick status bar or system bar.
         IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
         try {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index ba22f09..b30913a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -28,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Typeface;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -178,9 +179,10 @@
 
     private void updateOwnerInfo() {
         final ContentResolver res = getContext().getContentResolver();
-        final boolean ownerInfoEnabled = Settings.Secure.getInt(res,
-                Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1) != 0;
-        String text = Settings.Secure.getString(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO);
+        final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res,
+                Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
+        String text = Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO,
+                UserHandle.USER_CURRENT);
         if (ownerInfoEnabled && !TextUtils.isEmpty(text)) {
             maybeSetUpperCaseText(mOwnerInfoView, text);
             mOwnerInfoView.setVisibility(View.VISIBLE);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 416a0bb..212a6bb 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -339,7 +339,7 @@
 
         @Override
         public void onDeviceProvisioned() {
-            mContext.sendBroadcast(mUserPresentIntent);
+            sendUserPresentBroadcast();
         }
 
         @Override
@@ -511,6 +511,9 @@
             mUpdateMonitor.registerCallback(mUpdateCallback);
             doKeyguardLocked();
         }
+        // Most services aren't available until the system reaches the ready state, so we
+        // send it here when the device first boots.
+        maybeSendUserPresentBroadcast();
     }
 
     /**
@@ -606,6 +609,17 @@
                 notifyScreenOnLocked(showListener);
             }
         }
+        maybeSendUserPresentBroadcast();
+    }
+
+    private void maybeSendUserPresentBroadcast() {
+        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()
+                && mUserManager.getUsers(true).size() == 1) {
+            // Lock screen is disabled because the user has set the preference to "None".
+            // In this case, send out ACTION_USER_PRESENT here instead of in
+            // handleKeyguardDone()
+            sendUserPresentBroadcast();
+        }
     }
 
     /**
@@ -1093,6 +1107,10 @@
         }
         mWakeLock.release();
 
+        sendUserPresentBroadcast();
+    }
+
+    private void sendUserPresentBroadcast() {
         if (!(mContext instanceof Activity)) {
             final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
             mContext.sendBroadcastAsUser(mUserPresentIntent, currentUser);
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 385681e..9be7045 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
@@ -27,6 +28,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -193,31 +195,44 @@
         }, UserHandle.ALL, userFilter, null, null);
     }
 
+    private int getCallingOrCurrentUserId() {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid == android.os.Process.myUid()) {
+            try {
+                return ActivityManagerNative.getDefault().getCurrentUser().id;
+            } catch (RemoteException re) {
+                return UserHandle.getUserId(callingUid);
+            }
+        } else {
+            return UserHandle.getUserId(callingUid);
+        }
+    }
+
     @Override
     public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).allocateAppWidgetId(
+        return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
                 packageName, hostId);
     }
     
     @Override
     public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).deleteAppWidgetId(appWidgetId);
+        getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId);
     }
 
     @Override
     public void deleteHost(int hostId) throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).deleteHost(hostId);
+        getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId);
     }
 
     @Override
     public void deleteAllHosts() throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).deleteAllHosts();
+        getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts();
     }
 
     @Override
     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetId(appWidgetId, provider,
+        getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider,
                 options);
     }
 
@@ -225,34 +240,34 @@
     public boolean bindAppWidgetIdIfAllowed(
             String packageName, int appWidgetId, ComponentName provider, Bundle options)
                     throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetIdIfAllowed(
+        return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed(
                 packageName, appWidgetId, provider, options);
     }
 
     @Override
     public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).hasBindAppWidgetPermission(
+        return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission(
                 packageName);
     }
 
     @Override
     public void setBindAppWidgetPermission(String packageName, boolean permission)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).setBindAppWidgetPermission(
+        getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission(
                 packageName, permission);
     }
 
     @Override
     public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).bindRemoteViewsService(
+        getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService(
                 appWidgetId, intent, connection);
     }
 
     @Override
     public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
             List<RemoteViews> updatedViews) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).startListening(host,
+        return getImplForUser(getCallingOrCurrentUserId()).startListening(host,
                 packageName, hostId, updatedViews);
     }
 
@@ -287,27 +302,27 @@
 
     @Override
     public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetIds(provider);
+        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider);
     }
 
     @Override
     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetInfo(appWidgetId);
+        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId);
     }
 
     @Override
     public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetViews(appWidgetId);
+        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId);
     }
 
     @Override
     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
-        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetOptions(appWidgetId, options);
+        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options);
     }
 
     @Override
     public Bundle getAppWidgetOptions(int appWidgetId) {
-        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetOptions(appWidgetId);
+        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
     }
 
     static int[] getAppWidgetIds(Provider p) {
@@ -321,43 +336,43 @@
 
     @Override
     public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
-        return getImplForUser(UserHandle.getCallingUserId()).getInstalledProviders();
+        return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
     }
 
     @Override
     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).notifyAppWidgetViewDataChanged(
+        getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged(
                 appWidgetIds, viewId);
     }
 
     @Override
     public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).partiallyUpdateAppWidgetIds(
+        getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds(
                 appWidgetIds, views);
     }
 
     @Override
     public void stopListening(int hostId) throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).stopListening(hostId);
+        getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId);
     }
 
     @Override
     public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).unbindRemoteViewsService(
+        getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService(
                 appWidgetId, intent);
     }
 
     @Override
     public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetIds(appWidgetIds, views);
+        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views);
     }
 
     @Override
     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
             throws RemoteException {
-        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetProvider(provider, views);
+        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views);
     }
 
     @Override
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 815ee24..fcc8a06 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1627,22 +1627,22 @@
                                     Integer.parseInt(minWidthString, 16));
                         }
                         String minHeightString = parser.getAttributeValue(null, "min_height");
-                        if (minWidthString != null) {
+                        if (minHeightString != null) {
                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
                                     Integer.parseInt(minHeightString, 16));
                         }
-                        String maxWidthString = parser.getAttributeValue(null, "max_height");
-                        if (minWidthString != null) {
+                        String maxWidthString = parser.getAttributeValue(null, "max_width");
+                        if (maxWidthString != null) {
                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
                                     Integer.parseInt(maxWidthString, 16));
                         }
                         String maxHeightString = parser.getAttributeValue(null, "max_height");
-                        if (minWidthString != null) {
+                        if (maxHeightString != null) {
                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
                                     Integer.parseInt(maxHeightString, 16));
                         }
                         String categoryString = parser.getAttributeValue(null, "host_category");
-                        if (minWidthString != null) {
+                        if (categoryString != null) {
                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
                                     Integer.parseInt(categoryString, 16));
                         }
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index d4769e8..9b19008 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -46,6 +46,7 @@
     final private static String TAG = "IntentResolver";
     final private static boolean DEBUG = false;
     final private static boolean localLOGV = DEBUG || false;
+    final private static boolean VALIDATE = false;
 
     public void addFilter(F f) {
         if (localLOGV) {
@@ -67,16 +68,20 @@
                     mTypedActionToFilter, "      TypedAction: ");
         }
 
-        mOldResolver.addFilter(f);
-        verifyDataStructures(f);
+        if (VALIDATE) {
+            mOldResolver.addFilter(f);
+            verifyDataStructures(f);
+        }
     }
 
     public void removeFilter(F f) {
         removeFilterInternal(f);
         mFilters.remove(f);
 
-        mOldResolver.removeFilter(f);
-        verifyDataStructures(f);
+        if (VALIDATE) {
+            mOldResolver.removeFilter(f);
+            verifyDataStructures(f);
+        }
     }
 
     void removeFilterInternal(F f) {
@@ -314,12 +319,14 @@
         }
         sortResults(finalList);
 
-        List<R> oldList = mOldResolver.queryIntent(intent, resolvedType, defaultOnly, userId);
-        if (oldList.size() != finalList.size()) {
-            ValidationFailure here = new ValidationFailure();
-            here.fillInStackTrace();
-            Log.wtf(TAG, "Query result " + intent + " size is " + finalList.size()
-                    + "; old implementation is " + oldList.size(), here);
+        if (VALIDATE) {
+            List<R> oldList = mOldResolver.queryIntent(intent, resolvedType, defaultOnly, userId);
+            if (oldList.size() != finalList.size()) {
+                ValidationFailure here = new ValidationFailure();
+                here.fillInStackTrace();
+                Log.wtf(TAG, "Query result " + intent + " size is " + finalList.size()
+                        + "; old implementation is " + oldList.size(), here);
+            }
         }
 
         if (debug) {
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index e7f3599..20c89ad 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -50,9 +50,12 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
@@ -76,6 +79,7 @@
 
 import com.android.internal.R;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBarService;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -89,6 +93,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * This class is instantiated by the system as a system level service and can be
@@ -111,59 +116,23 @@
 
     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
 
-    private static final int MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG = 1;
-
-    private static final int MSG_TOGGLE_TOUCH_EXPLORATION = 2;
-
-    private static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 3;
-
-    private static final int MSG_SEND_UPDATE_INPUT_FILTER = 4;
-
     private static int sIdCounter = 0;
 
     private static int sNextWindowId;
 
-    final Context mContext;
+    private final Context mContext;
 
-    final Object mLock = new Object();
+    private final Object mLock = new Object();
 
-    final List<Service> mServices = new ArrayList<Service>();
+    private final SimpleStringSplitter mStringColonSplitter =
+            new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
 
-    final List<IAccessibilityManagerClient> mClients =
-        new ArrayList<IAccessibilityManagerClient>();
+    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
+            new ArrayList<AccessibilityServiceInfo>();
 
-    final Map<ComponentName, Service> mComponentNameToServiceMap = new HashMap<ComponentName, Service>();
+    private final PackageManager mPackageManager;
 
-    private final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<AccessibilityServiceInfo>();
-
-    private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
-
-    private final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<ComponentName>();
-
-    private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap =
-        new SparseArray<AccessibilityConnectionWrapper>();
-
-    private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>();
-
-    private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
-
-    private PackageManager mPackageManager;
-
-    private int mHandledFeedbackTypes = 0;
-
-    private boolean mIsAccessibilityEnabled;
-
-    private AccessibilityInputFilter mInputFilter;
-
-    private boolean mHasInputFilter;
-
-    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>();
-
-    private boolean mIsTouchExplorationEnabled;
-
-    private boolean mIsScreenMagnificationEnabled;
-
-    private final IWindowManager mWindowManager;
+    private final IWindowManager mWindowManagerService;
 
     private final SecurityPolicy mSecurityPolicy;
 
@@ -175,6 +144,35 @@
 
     private AlertDialog mEnableTouchExplorationDialog;
 
+    private AccessibilityInputFilter mInputFilter;
+
+    private boolean mHasInputFilter;
+
+    private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
+            new RemoteCallbackList<IAccessibilityManagerClient>();
+
+    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
+            new SparseArray<AccessibilityConnectionWrapper>();
+
+    private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
+
+    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+
+    private int mCurrentUserId = UserHandle.USER_NULL;
+
+    private UserState getCurrentUserStateLocked() {
+        return getUserStateLocked(mCurrentUserId);
+    }
+
+    private UserState getUserStateLocked(int userId) {
+        UserState state = mUserStates.get(userId);
+        if (state == null) {
+            state = new UserState(userId);
+            mUserStates.put(userId, state);
+        }
+        return state;
+    }
+
     /**
      * Creates a new instance.
      *
@@ -183,28 +181,27 @@
     public AccessibilityManagerService(Context context) {
         mContext = context;
         mPackageManager = mContext.getPackageManager();
-        mWindowManager = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
+        mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
-        registerPackageChangeAndBootCompletedBroadcastReceiver();
-        registerSettingsContentObservers();
+        registerBroadcastReceivers();
+        new AccessibilityContentObserver(mMainHandler).register(
+                context.getContentResolver());
     }
 
-    /**
-     * Registers a {@link BroadcastReceiver} for the events of
-     * adding/changing/removing/restarting a package and boot completion.
-     */
-    private void registerPackageChangeAndBootCompletedBroadcastReceiver() {
-        Context context = mContext;
-
+    private void registerBroadcastReceivers() {
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
                 synchronized (mLock) {
+                    if (getChangingUserId() != mCurrentUserId) {
+                        return;
+                    }
                     // We will update when the automation service dies.
                     if (mUiAutomationService == null) {
-                        populateInstalledAccessibilityServiceLocked();
-                        manageServicesLocked();
+                        UserState userState = getCurrentUserStateLocked();
+                        populateInstalledAccessibilityServiceLocked(userState);
+                        manageServicesLocked(userState);
                     }
                 }
             }
@@ -212,7 +209,12 @@
             @Override
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
-                    Iterator<ComponentName> it = mEnabledServices.iterator();
+                    final int userId = getChangingUserId();
+                    if (userId != mCurrentUserId) {
+                        return;
+                    }
+                    UserState state = getUserStateLocked(userId);
+                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
                     while (it.hasNext()) {
                         ComponentName comp = it.next();
                         String compPkg = comp.getPackageName();
@@ -221,13 +223,13 @@
                             // Update the enabled services setting.
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                                    mEnabledServices);
+                                    state.mEnabledServices, userId);
                             // Update the touch exploration granted services setting.
-                            mTouchExplorationGrantedServices.remove(comp);
+                            state.mTouchExplorationGrantedServices.remove(comp);
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.
                                             TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                    mEnabledServices);
+                                    state.mEnabledServices, userId);
                             return;
                         }
                     }
@@ -238,7 +240,12 @@
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
                 synchronized (mLock) {
-                    Iterator<ComponentName> it = mEnabledServices.iterator();
+                    final int userId = getChangingUserId();
+                    if (userId != mCurrentUserId) {
+                        return false;
+                    }
+                    UserState state = getUserStateLocked(userId);
+                    Iterator<ComponentName> it = state.mEnabledServices.iterator();
                     while (it.hasNext()) {
                         ComponentName comp = it.next();
                         String compPkg = comp.getPackageName();
@@ -250,179 +257,97 @@
                                 it.remove();
                                 persistComponentNamesToSettingLocked(
                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                                        mEnabledServices);
+                                        state.mEnabledServices, userId);
                             }
                         }
                     }
                     return false;
                 }
             }
-
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
-                    synchronized (mLock) {
-                        // We will update when the automation service dies.
-                        if (mUiAutomationService == null) {
-                            updateInternalStateLocked();
-                        }
-                    }
-                    return;
-                }
-                super.onReceive(context, intent);
-            }
         };
 
         // package changes
-        monitor.register(context, null, true);
+        monitor.register(mContext, null,  UserHandle.ALL, true);
 
-        // boot completed
-        IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
-        mContext.registerReceiver(monitor, bootFiler, null, monitor.getRegisteredHandler());
+        // user change
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                }
+            }
+        }, userFilter);
     }
 
-    /**
-     * {@link ContentObserver}s for {@link Settings.Secure#ACCESSIBILITY_ENABLED}
-     * and {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} settings.
-     */
-    private void registerSettingsContentObservers() {
-        ContentResolver contentResolver = mContext.getContentResolver();
-
-        Uri accessibilityEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_ENABLED);
-        contentResolver.registerContentObserver(accessibilityEnabledUri, false,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    super.onChange(selfChange);
-                    synchronized (mLock) {
-                        // We will update when the automation service dies.
-                        if (mUiAutomationService == null) {
-                            handleAccessibilityEnabledSettingChangedLocked();
-                            updateInputFilterLocked();
-                            sendStateToClientsLocked();
-                        }
-                    }
-                }
-            });
-
-        Uri touchExplorationRequestedUri = Settings.Secure.getUriFor(
-                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
-        contentResolver.registerContentObserver(touchExplorationRequestedUri, false,
-                new ContentObserver(new Handler()) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        super.onChange(selfChange);
-                        synchronized (mLock) {
-                            // We will update when the automation service dies.
-                            if (mUiAutomationService == null) {
-                                handleTouchExplorationEnabledSettingChangedLocked();
-                                updateInputFilterLocked();
-                                sendStateToClientsLocked();
-                            }
-                        }
-                    }
-                });
-
-        Uri accessibilityScreenMagnificationEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
-        contentResolver.registerContentObserver(accessibilityScreenMagnificationEnabledUri, false,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    super.onChange(selfChange);
-                    synchronized (mLock) {
-                        // We will update when the automation service dies.
-                        if (mUiAutomationService == null) {
-                            handleScreenMagnificationEnabledSettingChangedLocked();
-                            updateInputFilterLocked();
-                            sendStateToClientsLocked();
-                        }
-                    }
-                }
-            });
-
-        Uri accessibilityServicesUri =
-            Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
-        contentResolver.registerContentObserver(accessibilityServicesUri, false,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    super.onChange(selfChange);
-                    synchronized (mLock) {
-                        // We will update when the automation service dies.
-                        if (mUiAutomationService == null) {
-                            populateEnabledAccessibilityServicesLocked();
-                            manageServicesLocked();
-                        }
-                    }
-                }
-            });
-
-        Uri touchExplorationGrantedServicesUri = Settings.Secure.getUriFor(
-                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
-        contentResolver.registerContentObserver(touchExplorationGrantedServicesUri, false,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    super.onChange(selfChange);
-                    synchronized (mLock) {
-                        // We will update when the automation service dies.
-                        if (mUiAutomationService == null) {
-                            populateTouchExplorationGrantedAccessibilityServicesLocked();
-                            handleTouchExplorationGrantedAccessibilityServicesChangedLocked();
-                        }
-                    }
-                }
-            });
-    }
-
-    public int addClient(IAccessibilityManagerClient client) throws RemoteException {
+    public int addClient(IAccessibilityManagerClient client, int userId) {
         synchronized (mLock) {
-            final IAccessibilityManagerClient addedClient = client;
-            mClients.add(addedClient);
-            // Clients are registered all the time until their process is
-            // killed, therefore we do not have a corresponding unlinkToDeath.
-            client.asBinder().linkToDeath(new DeathRecipient() {
-                public void binderDied() {
-                    synchronized (mLock) {
-                        addedClient.asBinder().unlinkToDeath(this, 0);
-                        mClients.remove(addedClient);
-                    }
-                }
-            }, 0);
-            return getState();
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            // If the client is from a process that runs across users such as
+            // the system UI or the system we add it to the global state that
+            // is shared across users.
+            UserState userState = getUserStateLocked(resolvedUserId);
+            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
+                mGlobalClients.register(client);
+                return getClientState(userState);
+            } else {
+                userState.mClients.register(client);
+                // If this client is not for the current user we do not
+                // return a state since it is not for the foreground user.
+                // We will send the state to the client on a user switch.
+                return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
+            }
         }
     }
 
-    public boolean sendAccessibilityEvent(AccessibilityEvent event) {
+    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            // This method does nothing for a background user.
+            if (resolvedUserId != mCurrentUserId) {
+                return true; // yes, recycle the event
+            }
             if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
                 mSecurityPolicy.updateActiveWindowAndEventSourceLocked(event);
                 notifyAccessibilityServicesDelayedLocked(event, false);
                 notifyAccessibilityServicesDelayedLocked(event, true);
             }
             if (mHasInputFilter && mInputFilter != null) {
-                mMainHandler.obtainMessage(MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
+                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
                         AccessibilityEvent.obtain(event)).sendToTarget();
             }
             event.recycle();
-            mHandledFeedbackTypes = 0;
+            getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
         }
         return (OWN_PROCESS_ID != Binder.getCallingPid());
     }
 
-    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
+    public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
-            return mInstalledServices;
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            return getUserStateLocked(resolvedUserId).mInstalledServices;
         }
     }
 
-    public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
-        List<AccessibilityServiceInfo> result = mEnabledServicesForFeedbackTempList;
-        result.clear();
-        List<Service> services = mServices;
+    public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
+            int userId) {
+        List<AccessibilityServiceInfo> result = null;
         synchronized (mLock) {
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            result = mEnabledServicesForFeedbackTempList;
+            result.clear();
+            List<Service> services = getUserStateLocked(resolvedUserId).mServices;
             while (feedbackType != 0) {
                 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
                 feedbackType &= ~feedbackTypeBit;
@@ -438,30 +363,51 @@
         return result;
     }
 
-    public void interrupt() {
+    public void interrupt(int userId) {
+        CopyOnWriteArrayList<Service> services;
         synchronized (mLock) {
-            for (int i = 0, count = mServices.size(); i < count; i++) {
-                Service service = mServices.get(i);
-                try {
-                    service.mServiceInterface.onInterrupt();
-                } catch (RemoteException re) {
-                    Slog.e(LOG_TAG, "Error during sending interrupt request to "
-                        + service.mService, re);
-                }
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            // This method does nothing for a background user.
+            if (resolvedUserId != mCurrentUserId) {
+                return;
+            }
+            services = getUserStateLocked(resolvedUserId).mServices;
+        }
+        for (int i = 0, count = services.size(); i < count; i++) {
+            Service service = services.get(i);
+            try {
+                service.mServiceInterface.onInterrupt();
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error during sending interrupt request to "
+                    + service.mService, re);
             }
         }
     }
 
     public int addAccessibilityInteractionConnection(IWindow windowToken,
-            IAccessibilityInteractionConnection connection) throws RemoteException {
+            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
         synchronized (mLock) {
-            final IWindow addedWindowToken = windowToken;
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             final int windowId = sNextWindowId++;
-            AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(windowId,
-                    connection);
-            wrapper.linkToDeath();
-            mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder());
-            mWindowIdToInteractionConnectionWrapperMap.put(windowId, wrapper);
+            // If the window is from a process that runs across users such as
+            // the system UI or the system we add it to the global state that
+            // is shared across users.
+            if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
+                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+                        windowId, connection, UserHandle.USER_ALL);
+                wrapper.linkToDeath();
+                mGlobalInteractionConnections.put(windowId, wrapper);
+                mGlobalWindowTokens.put(windowId, windowToken.asBinder());
+            } else {
+                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+                        windowId, connection, resolvedUserId);
+                wrapper.linkToDeath();
+                UserState userState = getUserStateLocked(resolvedUserId);
+                userState.mInteractionConnections.put(windowId, wrapper);
+                userState.mWindowTokens.put(windowId, windowToken.asBinder());
+            }
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
             }
@@ -469,22 +415,47 @@
         }
     }
 
-    public void removeAccessibilityInteractionConnection(IWindow windowToken) {
+    public void removeAccessibilityInteractionConnection(IWindow window) {
         synchronized (mLock) {
-            final int count = mWindowIdToWindowTokenMap.size();
-            for (int i = 0; i < count; i++) {
-                if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) {
-                    final int windowId = mWindowIdToWindowTokenMap.keyAt(i);
-                    AccessibilityConnectionWrapper wrapper =
-                        mWindowIdToInteractionConnectionWrapperMap.get(windowId);
-                    wrapper.unlinkToDeath();
-                    removeAccessibilityInteractionConnectionLocked(windowId);
+            mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                    UserHandle.getCallingUserId());
+            IBinder token = window.asBinder();
+            final boolean removedGlobal =
+                    removeAccessibilityInteractionConnectionInternalLocked(
+                    token, mGlobalWindowTokens, mGlobalInteractionConnections);
+            if (removedGlobal) {
+                return;
+            }
+            final int userCount = mUserStates.size();
+            for (int i = 0; i < userCount; i++) {
+                UserState userState = mUserStates.valueAt(i);
+                final boolean removedForUser =
+                        removeAccessibilityInteractionConnectionInternalLocked(
+                        token, userState.mWindowTokens, userState.mInteractionConnections);
+                if (removedForUser) {
                     return;
                 }
             }
         }
     }
 
+    private boolean removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
+            SparseArray<IBinder> windowTokens,
+            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
+        final int count = windowTokens.size();
+        for (int i = 0; i < count; i++) {
+            if (windowTokens.valueAt(i) == windowToken) {
+                final int windowId = windowTokens.keyAt(i);
+                windowTokens.removeAt(i);
+                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
+                wrapper.unlinkToDeath();
+                interactionConnections.remove(windowId);
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
@@ -495,21 +466,18 @@
             // 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);
 
-            // Disable all services.
-            final int runningServiceCount = mServices.size();
-            for (int i = 0; i < runningServiceCount; i++) {
-                Service runningService = mServices.get(i);
-                runningService.unbind();
-            }
             // If necessary enable accessibility and announce that.
-            if (!mIsAccessibilityEnabled) {
-                mIsAccessibilityEnabled = true;
-                sendStateToClientsLocked();
+            if (!userState.mIsAccessibilityEnabled) {
+                userState.mIsAccessibilityEnabled = true;
+                scheduleSendStateToClientsLocked(userState);
             }
         }
         // Hook the automation service up.
-        mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
+        mUiAutomationService = new Service(mCurrentUserId, componentName,
+                accessibilityServiceInfo, true);
         mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
     }
 
@@ -572,30 +540,80 @@
      * @param outBounds The output to which to write the bounds.
      */
     boolean getActiveWindowBounds(Rect outBounds) {
+        IBinder token;
         synchronized (mLock) {
             final int windowId = mSecurityPolicy.mActiveWindowId;
-            IBinder token = mWindowIdToWindowTokenMap.get(windowId);
-            try {
-                WindowInfo info = mWindowManager.getWindowInfo(token);
-                if (info != null) {
-                    outBounds.set(info.frame);
-                    return true;
-                }
-            } catch (RemoteException re) {
-                /* ignore */
+            token = mGlobalWindowTokens.get(windowId);
+            if (token == null) {
+                token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
             }
-            return false;
+        }
+        WindowInfo info = null;
+        try {
+            info = mWindowManagerService.getWindowInfo(token);
+            if (info != null) {
+                outBounds.set(info.frame);
+                return true;
+            }
+        } catch (RemoteException re) {
+            /* ignore */
+        } finally {
+            if (info != null) {
+                info.recycle();
+            }
+        }
+        return false;
+    }
+
+    int getActiveWindowId() {
+        return mSecurityPolicy.mActiveWindowId;
+    }
+
+    private void switchUser(int userId) {
+        synchronized (mLock) {
+            if (userId == mCurrentUserId) {
+                return;
+            }
+
+            // Disconnect from services for the old user.
+            UserState oldUserState = getUserStateLocked(mCurrentUserId);
+            unbindAllServicesLocked(oldUserState);
+
+            // Disable the local managers for the old user.
+            if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
+                mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
+                        oldUserState.mUserId, 0).sendToTarget();
+            }
+
+            // The user changed.
+            mCurrentUserId = userId;
+
+            // Recreate the internal state for the new user.
+            mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
+                    mCurrentUserId, 0).sendToTarget();
+
+            // Re-register the test automation service after the new state is recreated.
+            if (mUiAutomationService != null) {
+                unregisterUiTestAutomationService(mUiAutomationService.mServiceInterface);
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = mUiAutomationService.mServiceInterface;
+                args.arg2 = mUiAutomationService.mAccessibilityServiceInfo;
+                mMainHandler.obtainMessage(MainHandler.MSG_REGISTER_UI_TEST_AUTOMATION_SERVICE,
+                        args).sendToTarget();
+            }
         }
     }
 
-    public int getActiveWindowId() {
-        return mSecurityPolicy.mActiveWindowId;
+    private void removeUser(int userId) {
+        synchronized (mLock) {
+            mUserStates.remove(userId);
+        }
     }
 
     private Service getQueryBridge() {
         if (mQueryBridge == null) {
             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-            mQueryBridge = new Service(null, info, true);
+            mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
         }
         return mQueryBridge;
     }
@@ -610,8 +628,9 @@
         //       gestures to avoid user frustration when different
         //       behavior is observed from different combinations of
         //       enabled accessibility services.
-        for (int i = mServices.size() - 1; i >= 0; i--) {
-            Service service = mServices.get(i);
+        UserState state = getCurrentUserStateLocked();
+        for (int i = state.mServices.size() - 1; i >= 0; i--) {
+            Service service = state.mServices.get(i);
             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
                 service.notifyGesture(gestureId);
                 return true;
@@ -624,29 +643,36 @@
      * Removes an AccessibilityInteractionConnection.
      *
      * @param windowId The id of the window to which the connection is targeted.
+     * @param userId The id of the user owning the connection. UserHandle.USER_ALL
+     *     if global.
      */
-    private void removeAccessibilityInteractionConnectionLocked(int windowId) {
-        mWindowIdToWindowTokenMap.remove(windowId);
-        mWindowIdToInteractionConnectionWrapperMap.remove(windowId);
+    private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            mGlobalWindowTokens.remove(windowId);
+            mGlobalInteractionConnections.remove(windowId);
+        } else {
+            UserState userState = getCurrentUserStateLocked();
+            userState.mWindowTokens.remove(windowId);
+            userState.mInteractionConnections.remove(windowId);
+        }
         if (DEBUG) {
             Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
         }
     }
 
-    /**
-     * Populates the cached list of installed {@link AccessibilityService}s.
-     */
-    private void populateInstalledAccessibilityServiceLocked() {
-        mInstalledServices.clear();
+    private void populateInstalledAccessibilityServiceLocked(UserState userState) {
+        userState.mInstalledServices.clear();
 
-        List<ResolveInfo> installedServices = mPackageManager.queryIntentServices(
+        List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
-                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                mCurrentUserId);
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
             ResolveInfo resolveInfo = installedServices.get(i);
             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(serviceInfo.permission)) {
+            if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
+                    serviceInfo.permission)) {
                 Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
                         serviceInfo.packageName, serviceInfo.name).flattenToShortString()
                         + ": it does not require the permission "
@@ -656,7 +682,7 @@
             AccessibilityServiceInfo accessibilityServiceInfo;
             try {
                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
-                mInstalledServices.add(accessibilityServiceInfo);
+                userState.mInstalledServices.add(accessibilityServiceInfo);
             } catch (XmlPullParserException xppe) {
                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
             } catch (IOException ioe) {
@@ -665,16 +691,19 @@
         }
     }
 
-    private void populateEnabledAccessibilityServicesLocked() {
+    private void populateEnabledAccessibilityServicesLocked(UserState userState) {
         populateComponentNamesFromSettingLocked(
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                mEnabledServices);
+                userState.mUserId,
+                userState.mEnabledServices);
     }
 
-    private void populateTouchExplorationGrantedAccessibilityServicesLocked() {
+    private void populateTouchExplorationGrantedAccessibilityServicesLocked(
+            UserState userState) {
         populateComponentNamesFromSettingLocked(
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                mTouchExplorationGrantedServices);
+                userState.mUserId,
+                userState.mTouchExplorationGrantedServices);
     }
 
     /**
@@ -687,12 +716,13 @@
     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
             boolean isDefault) {
         try {
-            for (int i = 0, count = mServices.size(); i < count; i++) {
-                Service service = mServices.get(i);
+            UserState state = getCurrentUserStateLocked();
+            for (int i = 0, count = state.mServices.size(); i < count; i++) {
+                Service service = state.mServices.get(i);
 
                 if (service.mIsDefault == isDefault) {
-                    if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) {
-                        mHandledFeedbackTypes |= service.mFeedbackType;
+                    if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
+                        state.mHandledFeedbackTypes |= service.mFeedbackType;
                         service.notifyAccessibilityEvent(event);
                     }
                 }
@@ -706,19 +736,21 @@
     }
 
     /**
-     * Adds a service.
+     * Adds a service for a user.
      *
      * @param service The service to add.
+     * @param userId The user id.
      */
-    private void tryAddServiceLocked(Service service) {
+    private void tryAddServiceLocked(Service service, int userId) {
         try {
-            if (mServices.contains(service) || !service.isConfigured()) {
+            UserState userState = getUserStateLocked(userId);
+            if (userState.mServices.contains(service) || !service.isConfigured()) {
                 return;
             }
             service.linkToOwnDeath();
-            mServices.add(service);
-            mComponentNameToServiceMap.put(service.mComponentName, service);
-            updateInputFilterLocked();
+            userState.mServices.add(service);
+            userState.mComponentNameToServiceMap.put(service.mComponentName, service);
+            updateInputFilterLocked(userState);
             tryEnableTouchExplorationLocked(service);
         } catch (RemoteException e) {
             /* do nothing */
@@ -732,14 +764,15 @@
      * @return True if the service was removed, false otherwise.
      */
     private boolean tryRemoveServiceLocked(Service service) {
-        final boolean removed = mServices.remove(service);
+        UserState userState = getUserStateLocked(service.mUserId);
+        final boolean removed = userState.mServices.remove(service);
         if (!removed) {
             return false;
         }
-        mComponentNameToServiceMap.remove(service.mComponentName);
+        userState.mComponentNameToServiceMap.remove(service.mComponentName);
         service.unlinkToOwnDeath();
         service.dispose();
-        updateInputFilterLocked();
+        updateInputFilterLocked(userState);
         tryDisableTouchExplorationLocked(service);
         return removed;
     }
@@ -791,23 +824,23 @@
     /**
      * Manages services by starting enabled ones and stopping disabled ones.
      */
-    private void manageServicesLocked() {
-        final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
-                mEnabledServices);
+    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 (mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
-            Settings.Secure.putInt(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+        if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
         }
     }
 
     /**
-     * Unbinds all bound services.
+     * Unbinds all bound services for a user.
+     *
+     * @param userState The user state.
      */
-    private void unbindAllServicesLocked() {
-        List<Service> services = mServices;
-
+    private void unbindAllServicesLocked(UserState userState) {
+        List<Service> services = userState.mServices;
         for (int i = 0, count = services.size(); i < count; i++) {
             Service service = services.get(i);
             if (service.unbind()) {
@@ -819,17 +852,17 @@
 
     /**
      * Populates a set with the {@link ComponentName}s stored in a colon
-     * separated value setting.
+     * separated value setting for a given user.
      *
      * @param settingName The setting to parse.
+     * @param userId The user id.
      * @param outComponentNames The output component names.
      */
-    private void populateComponentNamesFromSettingLocked(String settingName,
+    private void populateComponentNamesFromSettingLocked(String settingName, int userId,
             Set<ComponentName> outComponentNames) {
+        String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                settingName, userId);
         outComponentNames.clear();
-
-        String settingValue = Settings.Secure.getString(mContext.getContentResolver(), settingName);
-
         if (settingValue != null) {
             TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
             splitter.setString(settingValue);
@@ -854,7 +887,7 @@
      * @param componentNames The component names.
      */
     private void persistComponentNamesToSettingLocked(String settingName,
-            Set<ComponentName> componentNames) {
+            Set<ComponentName> componentNames, int userId) {
         StringBuilder builder = new StringBuilder();
         for (ComponentName componentName : componentNames) {
             if (builder.length() > 0) {
@@ -862,34 +895,34 @@
             }
             builder.append(componentName.flattenToShortString());
         }
-        Settings.Secure.putString(mContext.getContentResolver(), settingName, builder.toString());
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                settingName, builder.toString(), userId);
     }
 
     /**
      * Updates the state of each service by starting (or keeping running) enabled ones and
      * stopping the rest.
      *
-     * @param installedServices All installed {@link AccessibilityService}s.
-     * @param enabledServices The {@link ComponentName}s of the enabled services.
+     * @param userState The user state for which to do that.
      * @return The number of enabled installed services.
      */
-    private int updateServicesStateLocked(List<AccessibilityServiceInfo> installedServices,
-            Set<ComponentName> enabledServices) {
-
-        Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
-        boolean isEnabled = mIsAccessibilityEnabled;
+    private int updateServicesStateLocked(UserState userState) {
+        Map<ComponentName, Service> componentNameToServiceMap =
+                userState.mComponentNameToServiceMap;
+        boolean isEnabled = userState.mIsAccessibilityEnabled;
 
         int enabledInstalledServices = 0;
-        for (int i = 0, count = installedServices.size(); i < count; i++) {
-            AccessibilityServiceInfo installedService = installedServices.get(i);
+        for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
+            AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
             ComponentName componentName = ComponentName.unflattenFromString(
                     installedService.getId());
             Service service = componentNameToServiceMap.get(componentName);
 
             if (isEnabled) {
-                if (enabledServices.contains(componentName)) {
+                if (userState.mEnabledServices.contains(componentName)) {
                     if (service == null) {
-                        service = new Service(componentName, installedService, false);
+                        service = new Service(userState.mUserId, componentName,
+                                installedService, false);
                     }
                     service.bind();
                     enabledInstalledServices++;
@@ -908,145 +941,206 @@
         return enabledInstalledServices;
     }
 
-    /**
-     * Sends the state to the clients.
-     */
-    private void sendStateToClientsLocked() {
-        final int state = getState();
-        for (int i = 0, count = mClients.size(); i < count; i++) {
+    private void scheduleSendStateToClientsLocked(UserState userState) {
+        if (mGlobalClients.getRegisteredCallbackCount() > 0
+                || userState.mClients.getRegisteredCallbackCount() > 0) {
+            final int clientState = getClientState(userState);
+            mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
+                    clientState, userState.mUserId) .sendToTarget();
+        }
+    }
+
+    private void updateInputFilterLocked(UserState userState) {
+        boolean setInputFilter = false;
+        AccessibilityInputFilter inputFilter = null;
+        synchronized (mLock) {
+            if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled)
+                    || userState.mIsDisplayMagnificationEnabled) {
+                if (!mHasInputFilter) {
+                    mHasInputFilter = true;
+                    if (mInputFilter == null) {
+                        mInputFilter = new AccessibilityInputFilter(mContext,
+                                AccessibilityManagerService.this);
+                    }
+                    inputFilter = mInputFilter;
+                    setInputFilter = true;
+                }
+                int flags = 0;
+                if (userState.mIsDisplayMagnificationEnabled) {
+                    flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
+                }
+                if (userState.mIsTouchExplorationEnabled) {
+                    flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
+                }
+                mInputFilter.setEnabledFeatures(flags);
+            } else {
+                if (mHasInputFilter) {
+                    mHasInputFilter = false;
+                    mInputFilter.setEnabledFeatures(0);
+                    inputFilter = null;
+                    setInputFilter = true;
+                }
+            }
+        }
+        if (setInputFilter) {
             try {
-                mClients.get(i).setState(state);
+                mWindowManagerService.setInputFilter(inputFilter);
             } catch (RemoteException re) {
-                mClients.remove(i);
-                count--;
-                i--;
+                /* ignore */
             }
         }
     }
 
-    /**
-     * Gets the current state as a set of flags.
-     *
-     * @return The state.
-     */
-    private int getState() {
-        int state = 0;
-        if (mIsAccessibilityEnabled) {
-            state |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+    private void showEnableTouchExplorationDialog(final Service service) {
+        String label = service.mResolveInfo.loadLabel(
+                mContext.getPackageManager()).toString();
+        synchronized (mLock) {
+            final UserState state = getCurrentUserStateLocked();
+            if (state.mIsTouchExplorationEnabled) {
+                return;
+            }
+            if (mEnableTouchExplorationDialog != null
+                    && mEnableTouchExplorationDialog.isShowing()) {
+                return;
+            }
+            mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(android.R.string.ok, new OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        // The user allowed the service to toggle touch exploration.
+                        state.mTouchExplorationGrantedServices.add(service.mComponentName);
+                        persistComponentNamesToSettingLocked(
+                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                                       state.mTouchExplorationGrantedServices, state.mUserId);
+                        // Enable touch exploration.
+                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
+                                service.mUserId);
+                    }
+                })
+                .setNegativeButton(android.R.string.cancel, new OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    }
+                })
+                .setTitle(R.string.enable_explore_by_touch_warning_title)
+                .setMessage(mContext.getString(
+                        R.string.enable_explore_by_touch_warning_message, label))
+                .create();
+            mEnableTouchExplorationDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+            mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
+            mEnableTouchExplorationDialog.show();
+        }
+    }
+
+    private int getClientState(UserState userState) {
+        int clientState = 0;
+        if (userState.mIsAccessibilityEnabled) {
+            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
         }
         // Touch exploration relies on enabled accessibility.
-        if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
-            state |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+        if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
+            clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
         }
-        return state;
+        return clientState;
     }
 
-    /**
-     * Updates the state of the input filter.
-     */
-    private void updateInputFilterLocked() {
-         mMainHandler.obtainMessage(MSG_SEND_UPDATE_INPUT_FILTER).sendToTarget();
+    private void recreateInternalStateLocked(UserState userState) {
+        populateInstalledAccessibilityServiceLocked(userState);
+        populateEnabledAccessibilityServicesLocked(userState);
+        populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
+
+        handleTouchExplorationEnabledSettingChangedLocked(userState);
+        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
+        handleAccessibilityEnabledSettingChangedLocked(userState);
+
+        updateInputFilterLocked(userState);
+        scheduleSendStateToClientsLocked(userState);
     }
 
-    /**
-     * Updated the internal state of this service to match the current settings.
-     */
-    private void updateInternalStateLocked() {
-        populateInstalledAccessibilityServiceLocked();
-        populateEnabledAccessibilityServicesLocked();
-        populateTouchExplorationGrantedAccessibilityServicesLocked();
-
-        handleTouchExplorationEnabledSettingChangedLocked();
-        handleScreenMagnificationEnabledSettingChangedLocked();
-        handleAccessibilityEnabledSettingChangedLocked();
-
-        updateInputFilterLocked();
-        sendStateToClientsLocked();
-    }
-
-    /**
-     * Updated the state based on the accessibility enabled setting.
-     */
-    private void handleAccessibilityEnabledSettingChangedLocked() {
-        mIsAccessibilityEnabled = Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-        if (mIsAccessibilityEnabled) {
-            manageServicesLocked();
+    private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
+        userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
+               mContext.getContentResolver(),
+               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
+        if (userState.mIsAccessibilityEnabled ) {
+            manageServicesLocked(userState);
         } else {
-            unbindAllServicesLocked();
+            unbindAllServicesLocked(userState);
         }
     }
 
-    /**
-     * Updates the state based on the touch exploration enabled setting.
-     */
-    private void handleTouchExplorationEnabledSettingChangedLocked() {
-        mIsTouchExplorationEnabled = Settings.Secure.getInt(
+    private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
+        userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
-                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
     }
 
-    /**
-     * Updates the state based on the screen magnification enabled setting.
-     */
-    private void handleScreenMagnificationEnabledSettingChangedLocked() {
-        mIsScreenMagnificationEnabled = Settings.Secure.getInt(
+    private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
+        userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                0, userState.mUserId) == 1;
     }
 
-    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked() {
-        final int serviceCount = mServices.size();
+    private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
+            UserState userState) {
+        final int serviceCount = userState.mServices.size();
         for (int i = 0; i < serviceCount; i++) {
-            Service service = mServices.get(i);
+            Service service = userState.mServices.get(i);
             if (service.mRequestTouchExplorationMode
-                    && mTouchExplorationGrantedServices.contains(service.mComponentName)) {
+                    && userState.mTouchExplorationGrantedServices.contains(
+                            service.mComponentName)) {
                 tryEnableTouchExplorationLocked(service);
                 return;
             }
         }
-        if (mIsTouchExplorationEnabled) {
-            mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 0,
-                    0).sendToTarget();
+        if (userState.mIsTouchExplorationEnabled) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
         }
     }
 
     private void tryEnableTouchExplorationLocked(final Service service) {
-        if (!mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
-            final boolean canToggleTouchExploration = mTouchExplorationGrantedServices.contains(
-                    service.mComponentName);
+        UserState userState = getUserStateLocked(service.mUserId);
+        if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
+            final boolean canToggleTouchExploration =
+                    userState.mTouchExplorationGrantedServices.contains(service.mComponentName);
             if (!service.mIsAutomation && !canToggleTouchExploration) {
-                mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG,
-                        service).sendToTarget();
+                showEnableTouchExplorationDialog(service);
             } else {
-                mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 1, 0).sendToTarget();
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
             }
         }
     }
 
     private void tryDisableTouchExplorationLocked(Service service) {
-        if (mIsTouchExplorationEnabled) {
-            synchronized (mLock) {
-                final int serviceCount = mServices.size();
-                for (int i = 0; i < serviceCount; i++) {
-                    Service other = mServices.get(i);
-                    if (other != service && other.mRequestTouchExplorationMode) {
-                        return;
-                    }
+        UserState userState = getUserStateLocked(service.mUserId);
+        if (userState.mIsTouchExplorationEnabled) {
+            final int serviceCount = userState.mServices.size();
+            for (int i = 0; i < serviceCount; i++) {
+                Service other = userState.mServices.get(i);
+                if (other != service && other.mRequestTouchExplorationMode) {
+                    return;
                 }
-                mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 0, 0).sendToTarget();
             }
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
         }
     }
 
     private class AccessibilityConnectionWrapper implements DeathRecipient {
         private final int mWindowId;
+        private final int mUserId;
         private final IAccessibilityInteractionConnection mConnection;
 
         public AccessibilityConnectionWrapper(int windowId,
-                IAccessibilityInteractionConnection connection) {
+                IAccessibilityInteractionConnection connection, int userId) {
             mWindowId = windowId;
+            mUserId = userId;
             mConnection = connection;
         }
 
@@ -1062,12 +1156,17 @@
         public void binderDied() {
             unlinkToDeath();
             synchronized (mLock) {
-                removeAccessibilityInteractionConnectionLocked(mWindowId);
+                removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
             }
         }
     }
 
-    private class MainHandler extends Handler {
+    private final class MainHandler extends Handler {
+        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_REGISTER_UI_TEST_AUTOMATION_SERVICE = 5;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -1077,102 +1176,68 @@
         public void handleMessage(Message msg) {
             final int type = msg.what;
             switch (type) {
-                case MSG_TOGGLE_TOUCH_EXPLORATION: {
-                    final int value = msg.arg1;
-                    Settings.Secure.putInt(mContext.getContentResolver(),
-                            Settings.Secure.TOUCH_EXPLORATION_ENABLED, value);
-                } break;
-                case MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG: {
-                    final Service service = (Service) msg.obj;
-                    String label = service.mResolveInfo.loadLabel(
-                            mContext.getPackageManager()).toString();
-                    synchronized (mLock) {
-                        if (mIsTouchExplorationEnabled) {
-                            return;
-                        }
-                        if (mEnableTouchExplorationDialog != null
-                                && mEnableTouchExplorationDialog.isShowing()) {
-                            return;
-                        }
-                        mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
-                            .setIcon(android.R.drawable.ic_dialog_alert)
-                            .setPositiveButton(android.R.string.ok, new OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int which) {
-                                    // The user allowed the service to toggle touch exploration.
-                                    mTouchExplorationGrantedServices.add(service.mComponentName);
-                                    persistComponentNamesToSettingLocked(
-                                            Settings.Secure.
-                                                   TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                            mTouchExplorationGrantedServices);
-                                    // Enable touch exploration.
-                                    Settings.Secure.putInt(mContext.getContentResolver(),
-                                            Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1);
-                                }
-                            })
-                            .setNegativeButton(android.R.string.cancel, new OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                }
-                            })
-                            .setTitle(R.string.enable_explore_by_touch_warning_title)
-                            .setMessage(mContext.getString(
-                                R.string.enable_explore_by_touch_warning_message, label))
-                            .create();
-                        mEnableTouchExplorationDialog.getWindow().setType(
-                                WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
-                        mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
-                        mEnableTouchExplorationDialog.show();
-                    }
-                } break;
                 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
                     AccessibilityEvent event = (AccessibilityEvent) msg.obj;
-                    if (mHasInputFilter && mInputFilter != null) {
-                        mInputFilter.notifyAccessibilityEvent(event);
+                    synchronized (mLock) {
+                        if (mHasInputFilter && mInputFilter != null) {
+                            mInputFilter.notifyAccessibilityEvent(event);
+                        }
                     }
                     event.recycle();
                 } break;
-                case MSG_SEND_UPDATE_INPUT_FILTER: {
-                    boolean setInputFilter = false;
-                    AccessibilityInputFilter inputFilter = null;
+                case MSG_SEND_STATE_TO_CLIENTS: {
+                    final int clientState = msg.arg1;
+                    final int userId = msg.arg2;
+                    sendStateToClients(clientState, mGlobalClients);
+                    sendStateToClientsForUser(clientState, userId);
+                } break;
+                case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
+                    final int userId = msg.arg1;
+                    sendStateToClientsForUser(0, userId);
+                } break;
+                case MSG_SEND_RECREATE_INTERNAL_STATE: {
+                    final int userId = msg.arg1;
                     synchronized (mLock) {
-                        if ((mIsAccessibilityEnabled && mIsTouchExplorationEnabled)
-                                || mIsScreenMagnificationEnabled) {
-                            if (!mHasInputFilter) {
-                                mHasInputFilter = true;
-                                if (mInputFilter == null) {
-                                    mInputFilter = new AccessibilityInputFilter(mContext,
-                                            AccessibilityManagerService.this);
-                                }
-                                inputFilter = mInputFilter;
-                                setInputFilter = true;
-                            }
-                            int flags = 0;
-                            if (mIsScreenMagnificationEnabled) {
-                                flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
-                            }
-                            if (mIsTouchExplorationEnabled) {
-                                flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
-                            }
-                            mInputFilter.setEnabledFeatures(flags);
-                        } else {
-                            if (mHasInputFilter) {
-                                mHasInputFilter = false;
-                                mInputFilter.setEnabledFeatures(0);
-                                inputFilter = null;
-                                setInputFilter = true;
-                            }
-                        }
-                    }
-                    if (setInputFilter) {
-                        try {
-                            mWindowManager.setInputFilter(inputFilter);
-                        } catch (RemoteException re) {
-                            /* ignore */
-                        }
+                        UserState userState = getUserStateLocked(userId);
+                        recreateInternalStateLocked(userState);
                     }
                 } break;
+                case MSG_REGISTER_UI_TEST_AUTOMATION_SERVICE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        IAccessibilityServiceClient client =
+                                (IAccessibilityServiceClient) args.arg1;
+                        AccessibilityServiceInfo info = (AccessibilityServiceInfo) args.arg2;
+                        registerUiTestAutomationService(client, info);
+                    } finally {
+                        args.recycle();
+                    }
+                } break;
+            }
+        }
+
+        private void sendStateToClientsForUser(int clientState, int userId) {
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getUserStateLocked(userId);
+            }
+            sendStateToClients(clientState, userState.mClients);
+        }
+
+        private void sendStateToClients(int clientState,
+                RemoteCallbackList<IAccessibilityManagerClient> clients) {
+            try {
+                final int userClientCount = clients.beginBroadcast();
+                for (int i = 0; i < userClientCount; i++) {
+                    IAccessibilityManagerClient client = clients.getBroadcastItem(i);
+                    try {
+                        client.setState(clientState);
+                    } catch (RemoteException re) {
+                        /* ignore */
+                    }
+                }
+            } finally {
+                clients.finishBroadcast();
             }
         }
     }
@@ -1192,6 +1257,8 @@
         // used as message types allowing us to remove messages per event type. 
         private static final int MSG_ON_GESTURE = 0x80000000;
 
+        final int mUserId;
+
         int mId = 0;
 
         AccessibilityServiceInfo mAccessibilityServiceInfo;
@@ -1250,8 +1317,9 @@
             }
         };
 
-        public Service(ComponentName componentName,
+        public Service(int userId, ComponentName componentName,
                 AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
+            mUserId = userId;
             mResolveInfo = accessibilityServiceInfo.getResolveInfo();
             mId = sIdCounter++;
             mComponentName = componentName;
@@ -1312,7 +1380,7 @@
          */
         public boolean bind() {
             if (!mIsAutomation && mService == null) {
-                return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE);
+                return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId);
             }
             return false;
         }
@@ -1355,17 +1423,22 @@
 
         @Override
         public void setServiceInfo(AccessibilityServiceInfo info) {
-            synchronized (mLock) {
-                // If the XML manifest had data to configure the service its info
-                // should be already set. In such a case update only the dynamically
-                // configurable properties.
-                AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
-                if (oldInfo != null) {
-                    oldInfo.updateDynamicallyConfigurableProperties(info);
-                    setDynamicallyConfigurableProperties(oldInfo);
-                } else {
-                    setDynamicallyConfigurableProperties(info);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    // If the XML manifest had data to configure the service its info
+                    // should be already set. In such a case update only the dynamically
+                    // configurable properties.
+                    AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
+                    if (oldInfo != null) {
+                        oldInfo.updateDynamicallyConfigurableProperties(info);
+                        setDynamicallyConfigurableProperties(oldInfo);
+                    } else {
+                        setDynamicallyConfigurableProperties(info);
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
 
@@ -1376,7 +1449,7 @@
             try {
                 mServiceInterface.setConnection(this, mId);
                 synchronized (mLock) {
-                    tryAddServiceLocked(this);
+                    tryAddServiceLocked(this, mUserId);
                 }
             } catch (RemoteException re) {
                 Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
@@ -1388,14 +1461,21 @@
                 long accessibilityNodeId, int viewId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                                UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return -1;
+                }
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
                 if (!permissionGranted) {
                     return 0;
                 } else {
+                    resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
                         return 0;
@@ -1425,10 +1505,17 @@
                 long accessibilityNodeId, String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return -1;
+                }
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -1464,10 +1551,17 @@
                 long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
                 long interrogatingTid) throws RemoteException {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return -1;
+                }
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -1502,10 +1596,17 @@
                 int focusType, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return -1;
+                }
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -1540,10 +1641,17 @@
                 int direction, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return -1;
+                }
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -1576,10 +1684,19 @@
         @Override
         public boolean performAccessibilityAction(int accessibilityWindowId,
                 long accessibilityNodeId, int action, Bundle arguments, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) {
-            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
+                throws RemoteException {
+            final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return false;
+                }
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
                         resolvedWindowId, action, arguments);
                 if (!permissionGranted) {
@@ -1608,22 +1725,35 @@
             return true;
         }
 
-        public boolean performGlobalAction(int action) {
-            switch (action) {
-                case AccessibilityService.GLOBAL_ACTION_BACK: {
-                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
-                } return true;
-                case AccessibilityService.GLOBAL_ACTION_HOME: {
-                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
-                } return true;
-                case AccessibilityService.GLOBAL_ACTION_RECENTS: {
-                    openRecents();
-                } return true;
-                case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
-                    expandStatusBar();
-                } return true;
+        public boolean performGlobalAction(int action) throws RemoteException {
+            synchronized (mLock) {
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                        UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return false;
+                }
             }
-            return false;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                switch (action) {
+                    case AccessibilityService.GLOBAL_ACTION_BACK: {
+                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
+                    } return true;
+                    case AccessibilityService.GLOBAL_ACTION_HOME: {
+                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
+                    } return true;
+                    case AccessibilityService.GLOBAL_ACTION_RECENTS: {
+                        openRecents();
+                    } return true;
+                    case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
+                        expandStatusBar();
+                    } return true;
+                }
+                return false;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
 
         public void onServiceDisconnected(ComponentName componentName) {
@@ -1658,7 +1788,7 @@
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
                     mUiAutomationService = null;
-                    updateInternalStateLocked();
+                    recreateInternalStateLocked(getUserStateLocked(mUserId));
                 }
             }
         }
@@ -1817,8 +1947,10 @@
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
             }
-            AccessibilityConnectionWrapper wrapper = mWindowIdToInteractionConnectionWrapperMap.get(
-                    windowId);
+            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
+            if (wrapper == null) {
+                wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
+            }
             if (wrapper != null && wrapper.mConnection != null) {
                 return wrapper.mConnection;
             }
@@ -1828,7 +1960,7 @@
             return null;
         }
 
-        private int resolveAccessibilityWindowId(int accessibilityWindowId) {
+        private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
             if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
                 return mSecurityPolicy.mActiveWindowId;
             }
@@ -1836,9 +1968,15 @@
         }
 
         private float getCompatibilityScale(int windowId) {
-            IBinder windowToken = mWindowIdToWindowTokenMap.get(windowId);
             try {
-                return mWindowManager.getWindowCompatibilityScale(windowToken);
+                IBinder windowToken = mGlobalWindowTokens.get(windowId);
+                if (windowToken != null) {
+                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
+                }
+                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+                if (windowToken != null) {
+                    return mWindowManagerService.getWindowCompatibilityScale(windowToken);
+                }
             } catch (RemoteException re) {
                 /* ignore */
             }
@@ -1941,6 +2079,38 @@
             }
         }
 
+        public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID) {
+                return mCurrentUserId;
+            }
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (callingUserId == userId) {
+                return userId;
+            }
+            if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+                    && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
+                throw new SecurityException("Call from user " + callingUserId + " as user "
+                        + userId + " without permission INTERACT_ACROSS_USERS or "
+                        + "INTERACT_ACROSS_USERS_FULL not allowed.");
+            }
+            if (userId == UserHandle.USER_CURRENT
+                    || userId == UserHandle.USER_CURRENT_OR_SELF) {
+                return mCurrentUserId;
+            }
+            throw new IllegalArgumentException("Calling user can be changed to only "
+                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
+        }
+
+        public boolean isCallerInteractingAcrossUsers(int userId) {
+            final int callingUid = Binder.getCallingUid();
+            return (callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID
+                    || userId == UserHandle.USER_CURRENT
+                    || userId == UserHandle.USER_CURRENT_OR_SELF);
+        }
+
         private boolean isRetrievalAllowingWindow(int windowId) {
             return (mActiveWindowId == windowId);
         }
@@ -1953,22 +2123,25 @@
             if (OWN_PROCESS_ID == Binder.getCallingPid()) {
                 return;
             }
-            final int permissionStatus = mContext.checkCallingPermission(permission);
-            if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
+            if (!hasPermission(permission)) {
                 throw new SecurityException("You do not have " + permission
                         + " required to call " + function);
             }
         }
 
+        private boolean hasPermission(String permission) {
+            return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+        }
+
         private int getFocusedWindowId() {
             final long identity = Binder.clearCallingIdentity();
             try {
                 // We call this only on window focus change or after touch
                 // exploration gesture end and the shown windows are not that
                 // many, so the linear look up is just fine.
-                IBinder token = mWindowManager.getFocusedWindowToken();
+                IBinder token = mWindowManagerService.getFocusedWindowToken();
                 if (token != null) {
-                    SparseArray<IBinder> windows = mWindowIdToWindowTokenMap;
+                    SparseArray<IBinder> windows = getCurrentUserStateLocked().mWindowTokens;
                     final int windowCount = windows.size();
                     for (int i = 0; i < windowCount; i++) {
                         if (windows.valueAt(i) == token) {
@@ -1984,4 +2157,129 @@
             return -1;
         }
     }
+
+    private class UserState {
+        public final int mUserId;
+
+        public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
+
+        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
+            new RemoteCallbackList<IAccessibilityManagerClient>();
+
+        public final Map<ComponentName, Service> mComponentNameToServiceMap =
+                new HashMap<ComponentName, Service>();
+
+        public final List<AccessibilityServiceInfo> mInstalledServices =
+                new ArrayList<AccessibilityServiceInfo>();
+
+        public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
+
+        public final Set<ComponentName> mTouchExplorationGrantedServices =
+                new HashSet<ComponentName>();
+
+        public final SparseArray<AccessibilityConnectionWrapper>
+                mInteractionConnections =
+                new SparseArray<AccessibilityConnectionWrapper>();
+
+        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
+
+        public int mHandledFeedbackTypes = 0;
+
+        public boolean mIsAccessibilityEnabled;
+        public boolean mIsTouchExplorationEnabled;
+        public boolean mIsDisplayMagnificationEnabled;
+
+        public UserState(int userId) {
+            mUserId = userId;
+        }
+    }
+
+    private final class AccessibilityContentObserver extends ContentObserver {
+
+        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_ENABLED);
+
+        private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
+
+        private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+
+        private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+
+        private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
+                .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+
+        public AccessibilityContentObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void register(ContentResolver contentResolver) {
+            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
+                    false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
+                    false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
+                    false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
+                    false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mTouchExplorationGrantedAccessibilityServicesUri,
+                    false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (mAccessibilityEnabledUri.equals(uri)) {
+                synchronized (mLock) {
+                    // We will update when the automation service dies.
+                    if (mUiAutomationService == null) {
+                        UserState userState = getCurrentUserStateLocked();
+                        handleAccessibilityEnabledSettingChangedLocked(userState);
+                        updateInputFilterLocked(userState);
+                        scheduleSendStateToClientsLocked(userState);
+                    }
+                }
+            } else if (mTouchExplorationEnabledUri.equals(uri)) {
+                synchronized (mLock) {
+                    // We will update when the automation service dies.
+                    if (mUiAutomationService == null) {
+                        UserState userState = getCurrentUserStateLocked();
+                        handleTouchExplorationEnabledSettingChangedLocked(userState);
+                        updateInputFilterLocked(userState);
+                        scheduleSendStateToClientsLocked(userState);
+                    }
+                }
+            } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
+                synchronized (mLock) {
+                    // We will update when the automation service dies.
+                    if (mUiAutomationService == null) {
+                        UserState userState = getCurrentUserStateLocked();
+                        handleDisplayMagnificationEnabledSettingChangedLocked(userState);
+                        updateInputFilterLocked(userState);
+                        scheduleSendStateToClientsLocked(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);
+                    }
+                }
+            } 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);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index cb6b31a..c84f988 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -1150,20 +1150,9 @@
                 return;
             }
 
-            if (Build.IS_DEBUGGABLE) {
-                if (mSendHoverEnterDelayed.isPending()) {
-                    throw new IllegalStateException("mSendHoverEnterDelayed must not be pending.");
-                }
-                if (mSendHoverExitDelayed.isPending()) {
-                    throw new IllegalStateException("mSendHoverExitDelayed must not be pending.");
-                }
-                if (!mPerformLongPressDelayed.isPending()) {
-                    throw new IllegalStateException(
-                            "mPerformLongPressDelayed must not be pending.");
-                }
-            }
-
             // Remove pending event deliveries.
+            mSendHoverEnterDelayed.remove();
+            mSendHoverExitDelayed.remove();
             mPerformLongPressDelayed.remove();
 
             // The touch interaction has ended since we will send a click.
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 05ff379..32907f8 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -4329,6 +4329,9 @@
         if (resumed != null && resumed.thumbHolder == tr) {
             info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
         }
+        if (info.mainThumbnail == null) {
+            info.mainThumbnail = tr.lastThumbnail;
+        }
         return info;
     }
 
@@ -4343,7 +4346,7 @@
         // thumbnail to return.
         TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
         if (info.numSubThumbbails <= 0) {
-            return info.mainThumbnail;
+            return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
         } else {
             return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
         }
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 46bcc4a..fd9fc98 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -25,6 +25,7 @@
 import android.os.Message;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -98,7 +99,7 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        final int stateFlagsDisabled = mManagerService.addClient(mockClient);
+        final int stateFlagsDisabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
         boolean enabledAccessibilityDisabled =
             (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -110,7 +111,7 @@
         ensureAccessibilityEnabled(mContext, true);
 
         // invoke the method under test
-        final int stateFlagsEnabled = mManagerService.addClient(mockClient);
+        final int stateFlagsEnabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
         boolean enabledAccessibilityEnabled =
             (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -129,7 +130,7 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        final int stateFlagsEnabled = mManagerService.addClient(mockClient);
+        final int stateFlagsEnabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
         boolean enabledAccessibilityEnabled =
             (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -141,7 +142,7 @@
         ensureAccessibilityEnabled(mContext, false);
 
         // invoke the method under test
-        final int stateFlagsDisabled = mManagerService.addClient(mockClient);
+        final int stateFlagsDisabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
         boolean enabledAccessibilityDisabled =
             (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -160,7 +161,8 @@
         String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName();
 
         // look for the two mock services
-        for (AccessibilityServiceInfo info : mManagerService.getInstalledAccessibilityServiceList()) {
+        for (AccessibilityServiceInfo info : mManagerService.getInstalledAccessibilityServiceList(
+                UserHandle.USER_OWNER)) {
             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
             if (packageName.equals(serviceInfo.packageName)) {
                 if (firstMockServiceClassName.equals(serviceInfo.name)) {
@@ -201,7 +203,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -231,7 +233,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -261,7 +263,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -297,8 +299,8 @@
         service.replay();
 
         // send the events
-        mManagerService.sendAccessibilityEvent(firstEvent);
-        mManagerService.sendAccessibilityEvent(secondEvent);
+        mManagerService.sendAccessibilityEvent(firstEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(secondEvent, UserHandle.USER_OWNER);
 
         // wait for #sendAccessibilityEvent to reach the backing service
         Thread.sleep(TIMEOUT_BINDER_CALL);
@@ -354,7 +356,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -393,7 +395,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -434,7 +436,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -477,7 +479,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -512,7 +514,7 @@
         secondService.replay();
 
         // call the method under test
-        mManagerService.interrupt();
+        mManagerService.interrupt(UserHandle.USER_OWNER);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index e083815..e7366ea 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -26,7 +26,7 @@
 import org.easymock.IArgumentMatcher;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -70,14 +70,16 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
+                UserHandle.USER_OWNER)).andReturn(
                 AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        expect(mockServiceInterface.getInstalledAccessibilityServiceList()).andReturn(
-                expectedServices);
+        expect(mockServiceInterface.getInstalledAccessibilityServiceList(UserHandle.USER_OWNER))
+                .andReturn(expectedServices);
         replay(mockServiceInterface);
 
         // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
+                UserHandle.USER_OWNER);
         List<AccessibilityServiceInfo> receivedServices =
             manager.getInstalledAccessibilityServiceList();
 
@@ -92,13 +94,15 @@
     public void testInterrupt() throws Exception {
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
-                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        mockServiceInterface.interrupt();
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
+                UserHandle.USER_OWNER)).andReturn(
+                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
+        mockServiceInterface.interrupt(UserHandle.USER_OWNER);
         replay(mockServiceInterface);
 
         // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
+                UserHandle.USER_OWNER);
         manager.interrupt();
 
         // verify the mock service was properly called
@@ -109,12 +113,14 @@
     public void testIsEnabled() throws Exception {
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
-                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
+                UserHandle.USER_OWNER)).andReturn(
+                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
         replay(mockServiceInterface);
 
         // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
+                UserHandle.USER_OWNER);
         boolean isEnabledServiceEnabled = manager.isEnabled();
 
         // check expected result
@@ -144,16 +150,18 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
-                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
-                .andReturn(true);
-        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
-                .andReturn(false);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
+                UserHandle.USER_OWNER)).andReturn(
+                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
+        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
+                UserHandle.USER_OWNER)).andReturn(true);
+        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
+                UserHandle.USER_OWNER)).andReturn(false);
         replay(mockServiceInterface);
 
         // invoke the method under test (manager and service in different processes)
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
+                UserHandle.USER_OWNER);
         manager.sendAccessibilityEvent(sentEvent);
 
         // check expected result
@@ -180,11 +188,13 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(0);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
+                UserHandle.USER_OWNER)).andReturn(0);
         replay(mockServiceInterface);
 
         // invoke the method under test (accessibility disabled)
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface);
+        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
+                UserHandle.USER_OWNER);
         try {
             manager.sendAccessibilityEvent(sentEvent);
             fail("No accessibility events are sent if accessibility is disabled");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index cd7ee76..7b7a7b3 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -38,10 +38,8 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -216,6 +214,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
         throw new UnsupportedOperationException();
@@ -223,7 +227,7 @@
 
     /** @hide */
     @Override
-    public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+    public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                                                    int flags, int userId) {
         throw new UnsupportedOperationException();
     }
@@ -255,6 +259,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags) {
         throw new UnsupportedOperationException();
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
index bd56d62..4715d6e 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
@@ -124,6 +124,11 @@
                 android:layout_marginRight="10sp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/benchmark_all"
+                    android:onClick="benchmark_all"/>
             </LinearLayout>
     </ScrollView>
 </LinearLayout>
diff --git a/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
index cc5cc4d..a7dd165 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
@@ -29,5 +29,6 @@
     <string name="gamma">Gamma</string>
     <string name="saturation">Saturation</string>
     <string name="benchmark">Benchmark</string>
+    <string name="benchmark_all">Benchmark All</string>
 
 </resources>
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 7b84355..5311399 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -39,9 +39,21 @@
 import android.util.Log;
 import java.lang.Math;
 
+import android.os.Environment;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
 public class ImageProcessingActivity extends Activity
                                        implements SeekBar.OnSeekBarChangeListener {
     private final String TAG = "Img";
+    private final String RESULT_FILE = "image_processing_result.csv";
+
     Bitmap mBitmapIn;
     Bitmap mBitmapOut;
     String mTestNames[];
@@ -203,6 +215,9 @@
         case 26:
             mTest = new Convolve5x5(true);
             break;
+        case 27:
+            mTest = new Mandelbrot();
+            break;
         }
 
         mTest.createBaseTest(this, mBitmapIn);
@@ -215,7 +230,7 @@
     }
 
     void setupTests() {
-        mTestNames = new String[27];
+        mTestNames = new String[28];
         mTestNames[0] = "Levels Vec3 Relaxed";
         mTestNames[1] = "Levels Vec4 Relaxed";
         mTestNames[2] = "Levels Vec3 Full";
@@ -243,6 +258,8 @@
         mTestNames[24] = "CrossProcess (using LUT)";
         mTestNames[25] = "Convolve 5x5";
         mTestNames[26] = "Intrinsics Convolve 5x5";
+        mTestNames[27] = "Mandelbrot";
+
         mTestSpinner.setAdapter(new ArrayAdapter<String>(
             this, R.layout.spinner_layout, mTestNames));
     }
@@ -320,6 +337,33 @@
         //long javaTime = javaFilter();
         //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
         mBenchmarkResult.setText("Result: " + t + " ms");
+        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
+    }
+
+    public void benchmark_all(View v) {
+        // write result into a file
+        File externalStorage = Environment.getExternalStorageDirectory();
+        if (!externalStorage.canWrite()) {
+            Log.v(TAG, "sdcard is not writable");
+            return;
+        }
+        File resultFile = new File(externalStorage, RESULT_FILE);
+        resultFile.setWritable(true, false);
+        try {
+            BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
+            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
+            for (int i = 0; i < mTestNames.length; i++ ) {
+                changeTest(i);
+                float t = getBenchmark();
+                String s = new String("" + mTestNames[i] + ", " + t);
+                rsWriter.write(s + "\n");
+                Log.v(TAG, "Test " + s + "ms\n");
+            }
+            rsWriter.close();
+        } catch (IOException e) {
+            Log.v(TAG, "Unable to write result file " + e.getMessage());
+        }
+        changeTest(0);
     }
 
     // For benchmark test
@@ -329,7 +373,7 @@
         mTest.setupBenchmark();
         long result = 0;
 
-        Log.v(TAG, "Warming");
+        //Log.v(TAG, "Warming");
         long t = java.lang.System.currentTimeMillis() + 2000;
         do {
             mTest.runTest();
@@ -337,17 +381,18 @@
         } while (t > java.lang.System.currentTimeMillis());
 
 
-        Log.v(TAG, "Benchmarking");
+        //Log.v(TAG, "Benchmarking");
+        int ct = 0;
         t = java.lang.System.currentTimeMillis();
-        for (int i=0; i<10; i++) {
+        do {
             mTest.runTest();
-        }
-        mTest.finish();
+            mTest.finish();
+            ct++;
+        } while ((t+5000) > java.lang.System.currentTimeMillis());
         t = java.lang.System.currentTimeMillis() - t;
         float ft = (float)t;
-        ft /= 10;
+        ft /= ct;
 
-        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + ft);
         mTest.exitBenchmark();
         mDoingBenchmark = false;
 
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java
new file mode 100644
index 0000000..20036e6
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Mandelbrot extends TestBase {
+    private ScriptC_mandelbrot mScript;
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Iterations");
+        b.setProgress(0);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        int iters = progress * 3 + 50;
+        mScript.set_gMaxIteration(iters);
+    }
+
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        t.setText("Lower Bound: X");
+        b.setProgress(0);
+        return true;
+    }
+
+    public void onBar2Changed(int progress) {
+        float scaleFactor = mScript.get_scaleFactor();
+        // allow viewport to be moved by 2x scale factor
+        float lowerBoundX = -2.f + ((progress / scaleFactor) / 50.f);
+        mScript.set_lowerBoundX(lowerBoundX);
+    }
+
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        t.setText("Lower Bound: Y");
+        b.setProgress(0);
+        return true;
+    }
+
+    public void onBar3Changed(int progress) {
+        float scaleFactor = mScript.get_scaleFactor();
+        // allow viewport to be moved by 2x scale factor
+        float lowerBoundY = -2.f + ((progress / scaleFactor) / 50.f);
+        mScript.set_lowerBoundY(lowerBoundY);
+    }
+
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        t.setText("Scale Factor");
+        b.setProgress(0);
+        return true;
+    }
+
+    public void onBar4Changed(int progress) {
+        float scaleFactor = 4.f - (3.96f * (progress / 100.f));
+        mScript.set_scaleFactor(scaleFactor);
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        int width = mOutPixelsAllocation.getType().getX();
+        int height = mOutPixelsAllocation.getType().getY();
+
+        mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot);
+        mScript.set_gDimX(width);
+        mScript.set_gDimY(height);
+        mScript.set_gMaxIteration(50);
+    }
+
+    public void runTest() {
+        mScript.forEach_root(mOutPixelsAllocation);
+        mRS.finish();
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs
new file mode 100644
index 0000000..da81d2e
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs
@@ -0,0 +1,56 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+
+uint32_t gMaxIteration = 500;
+uint32_t gDimX = 1024;
+uint32_t gDimY = 1024;
+
+float lowerBoundX = -2.f;
+float lowerBoundY = -2.f;
+float scaleFactor = 4.f;
+
+void root(uchar4 *v_out, uint32_t x, uint32_t y) {
+  float2 p;
+  p.x = lowerBoundX + ((float)x / gDimX) * scaleFactor;
+  p.y = lowerBoundY + ((float)y / gDimY) * scaleFactor;
+
+  float2 t = 0;
+  float2 t2 = t * t;
+  int iter = 0;
+  while((t2.x + t2.y < 4.f) && (iter < gMaxIteration)) {
+    float xtemp = t2.x - t2.y + p.x;
+    t.y = 2 * t.x * t.y + p.y;
+    t.x = xtemp;
+    iter++;
+    t2 = t * t;
+  }
+
+  if(iter >= gMaxIteration) {
+    // write a non-transparent black pixel
+    *v_out = (uchar4){0, 0, 0, 0xff};
+  } else {
+    float mi3 = gMaxIteration / 3.;
+    if (iter <= (gMaxIteration / 3))
+      *v_out = (uchar4){0xff * (iter / mi3), 0, 0, 0xff};
+    else if (iter <= (((gMaxIteration / 3) * 2)))
+      *v_out = (uchar4){0xff - (0xff * ((iter - mi3) / mi3)),
+                        (0xff * ((iter - mi3) / mi3)), 0, 0xff};
+    else
+      *v_out = (uchar4){0, 0xff - (0xff * ((iter - (mi3 * 2)) / mi3)),
+                        (0xff * ((iter - (mi3 * 2)) / mi3)), 0xff};
+  }
+}