Merge "Do not prematurely update position while bounds animating." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 61345fd..7fe5728 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29146,7 +29146,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -43630,6 +43629,7 @@
     method public void setSharedElementsUseOverlay(boolean);
     method public void setSoftInputMode(int);
     method public abstract void setStatusBarColor(int);
+    method public void setSustainedPerformanceMode(boolean);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionBackgroundFadeDuration(long);
@@ -58086,6 +58086,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59068,6 +59069,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/system-current.txt b/api/system-current.txt
index d44e157..dfaae6b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31574,7 +31574,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -46579,6 +46578,7 @@
     method public void setSharedElementsUseOverlay(boolean);
     method public void setSoftInputMode(int);
     method public abstract void setStatusBarColor(int);
+    method public void setSustainedPerformanceMode(boolean);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionBackgroundFadeDuration(long);
@@ -61392,6 +61392,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -62374,6 +62375,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4020993..88031cf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29214,7 +29214,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -43707,6 +43706,7 @@
     method public void setSharedElementsUseOverlay(boolean);
     method public void setSoftInputMode(int);
     method public abstract void setStatusBarColor(int);
+    method public void setSustainedPerformanceMode(boolean);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionBackgroundFadeDuration(long);
@@ -58164,6 +58164,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59146,6 +59147,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 271ec79..1ff2e8a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -590,7 +590,7 @@
         if (mService != null) try {
             mRemovalCallback = callback;
             mRemovalFingerprint = fp;
-            mService.remove(mToken, fp.getFingerId(), userId, mServiceReceiver);
+            mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception in remove: ", e);
             if (callback != null) {
@@ -810,11 +810,13 @@
             if (mRemovalCallback != null) {
                 int reqFingerId = mRemovalFingerprint.getFingerId();
                 int reqGroupId = mRemovalFingerprint.getGroupId();
-                if (reqFingerId != 0  &&  fingerId != reqFingerId) {
+                if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {
                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+                    return;
                 }
                 if (groupId != reqGroupId) {
                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+                    return;
                 }
                 mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
                         deviceId));
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index d7915e3..a83397a 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -41,7 +41,8 @@
     void cancelEnrollment(IBinder token);
 
     // Any errors resulting from this call will be returned to the listener
-    void remove(IBinder token, int fingerId, int groupId, IFingerprintServiceReceiver receiver);
+    void remove(IBinder token, int fingerId, int groupId, int userId,
+            IFingerprintServiceReceiver receiver);
 
     // Rename the fingerprint specified by fingerId and groupId to the given name
     void rename(int fingerId, int groupId, String name);
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 89edaa9..0c3d4b3 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -43,6 +43,12 @@
     private Handler mCallbackHandler;
 
     /**
+     * @deprecated Use {@code mCallback} instead.
+     */
+    @Deprecated
+    private ICallback mLocalCallback;
+
+    /**
      * An interface to receive asynchronous communication from the context hub.
      */
     public abstract static class Callback {
@@ -64,6 +70,24 @@
     }
 
     /**
+     * @deprecated Use {@link Callback} instead.
+     * @hide
+     */
+    @Deprecated
+    public interface ICallback {
+        /**
+         * Callback function called on message receipt from context hub.
+         *
+         * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
+         * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
+         * @param message The context hub message.
+         *
+         * @see ContextHubMessage
+         */
+        void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message);
+    }
+
+    /**
      * Get a handle to all the context hubs in the system
      * @return array of context hub handles
      */
@@ -223,6 +247,20 @@
     }
 
     /**
+     * @deprecated Use {@link #registerCallback(Callback)} instead.
+     * @hide
+     */
+    @Deprecated
+    public int registerCallback(ICallback callback) {
+        if (mLocalCallback != null) {
+            Log.w(TAG, "Max number of local callbacks reached!");
+            return -1;
+        }
+        mLocalCallback = callback;
+        return 0;
+    }
+
+    /**
      * Set a callback to receive messages from the context hub
      *
      * @param callback Callback object
@@ -266,6 +304,19 @@
       return 0;
     }
 
+    /**
+     * @deprecated Use {@link #unregisterCallback(Callback)} instead.
+     * @hide
+     */
+    public synchronized int unregisterCallback(ICallback callback) {
+        if (callback != mLocalCallback) {
+            Log.w(TAG, "Cannot recognize local callback!");
+            return -1;
+        }
+        mLocalCallback = null;
+        return 0;
+    }
+
     private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
         @Override
         public void onMessageReceipt(final int hubId, final int nanoAppId,
@@ -282,6 +333,12 @@
                         }
                     });
                 }
+            } else if (mLocalCallback != null) {
+                // we always ensure that mCallback takes precedence, because mLocalCallback is only
+                // for internal compatibility
+                synchronized (this) {
+                    mLocalCallback.onMessageReceipt(hubId, nanoAppId, message);
+                }
             } else {
                 Log.d(TAG, "Context hub manager client callback is NULL");
             }
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 2b9b974..8176189 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -57,19 +58,17 @@
     private static final int OS_APP_INSTANCE = -1;
 
     private final Context mContext;
-
-    private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
-    private ContextHubInfo[] mContextHubInfo;
-    private IContextHubCallback mCallback;
+    private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
+    private final ContextHubInfo[] mContextHubInfo;
+    private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
+            new RemoteCallbackList<>();
 
     private native int nativeSendMessage(int[] header, byte[] data);
     private native ContextHubInfo[] nativeInitialize();
 
-
     public ContextHubService(Context context) {
         mContext = context;
         mContextHubInfo = nativeInitialize();
-        mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
 
         for (int i = 0; i < mContextHubInfo.length; i++) {
             Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
@@ -80,9 +79,7 @@
     @Override
     public int registerCallback(IContextHubCallback callback) throws RemoteException {
         checkPermissions();
-        synchronized (this) {
-            mCallback = callback;
-        }
+        mCallbacksList.register(callback);
         return 0;
     }
 
@@ -237,26 +234,26 @@
         if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
             return  -1;
         }
-
-        synchronized (this) {
-            if (mCallback != null) {
-                ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
-                                                              header[MSG_FIELD_VERSION],
-                                                              data);
-
-                try {
-                    mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
-                                               header[MSG_FIELD_APP_INSTANCE],
-                                               msg);
-                } catch (Exception e) {
-                    Log.w(TAG, "Exception " + e + " when calling remote callback");
-                    return -1;
-                }
-            } else {
-                Log.d(TAG, "Message Callback is NULL");
+        int callbacksCount = mCallbacksList.beginBroadcast();
+        if (callbacksCount < 1) {
+            Log.v(TAG, "No message callbacks registered.");
+            return 0;
+        }
+        ContextHubMessage message =
+                new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data);
+        for (int i = 0; i < callbacksCount; ++i) {
+            IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
+            try {
+                callback.onMessageReceipt(
+                        header[MSG_FIELD_HUB_HANDLE],
+                        header[MSG_FIELD_APP_INSTANCE],
+                        message);
+            } catch (RemoteException e) {
+                Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
+                continue;
             }
         }
-
+        mCallbacksList.finishBroadcast();
         return 0;
     }
 
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index e842ec6..71a5a88 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -17,10 +17,14 @@
 package android.hardware.location;
 
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import libcore.util.EmptyArray;
+
 /**
  * @hide
  */
@@ -43,6 +47,8 @@
     private int mHandle;
 
     public NanoAppInstanceInfo() {
+        mNeededSensors = EmptyArray.INT;
+        mOutputEvents = EmptyArray.INT;
     }
 
     /**
@@ -193,6 +199,7 @@
      *
      * @return int[] all the required sensors needed by this app
      */
+    @NonNull
     public int[] getNeededSensors() {
         return mNeededSensors;
     }
@@ -204,8 +211,8 @@
      *
      * @hide
      */
-    public void setNeededSensors(int[] neededSensors) {
-        mNeededSensors = neededSensors;
+    public void setNeededSensors(@Nullable int[] neededSensors) {
+        mNeededSensors = neededSensors != null ? neededSensors : EmptyArray.INT;
     }
 
     /**
@@ -213,6 +220,7 @@
      *
      * @return all the events that can be generated by this app
      */
+    @NonNull
     public int[] getOutputEvents() {
         return mOutputEvents;
     }
@@ -225,8 +233,8 @@
      *
      * @hide
      */
-    public void setOutputEvents(int[] outputEvents) {
-        mOutputEvents = outputEvents;
+    public void setOutputEvents(@Nullable int[] outputEvents) {
+        mOutputEvents = outputEvents != null ? outputEvents : EmptyArray.INT;
     }
 
     /**
@@ -280,12 +288,12 @@
         mNeededWriteMemBytes = in.readInt();
         mNeededExecMemBytes = in.readInt();
 
-        int mNeededSensorsLength = in.readInt();
-        mNeededSensors = new int[mNeededSensorsLength];
+        int neededSensorsLength = in.readInt();
+        mNeededSensors = new int[neededSensorsLength];
         in.readIntArray(mNeededSensors);
 
-        int mOutputEventsLength = in.readInt();
-        mOutputEvents = new int[mOutputEventsLength];
+        int outputEventsLength = in.readInt();
+        mOutputEvents = new int[outputEventsLength];
         in.readIntArray(mOutputEvents);
     }
 
@@ -303,9 +311,9 @@
         out.writeInt(mNeededWriteMemBytes);
         out.writeInt(mNeededExecMemBytes);
 
+        // arrays are never null
         out.writeInt(mNeededSensors.length);
         out.writeIntArray(mNeededSensors);
-
         out.writeInt(mOutputEvents.length);
         out.writeIntArray(mOutputEvents);
     }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 92edc62..16d90de 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,15 +219,6 @@
     public static final int DRAW_WAKE_LOCK = 0x00000080;
 
     /**
-     * Wake lock level: Enables Sustained Performance Mode.
-     * <p>
-     * This is used by Gaming and VR applications to ensure the device
-     * will provide consistent performance over a large amount of time.
-     * </p>
-     */
-    public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
-
-    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -559,7 +550,6 @@
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
             case DRAW_WAKE_LOCK:
-            case SUSTAINED_PERFORMANCE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9801e1b..b3cf710 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -55,12 +55,16 @@
 
 
     /**
-     * Power hint: The user is interacting with the device. The corresponding data field must be
+     * Power hint:
+     * Interaction: The user is interacting with the device. The corresponding data field must be
      * the expected duration of the fling, or 0 if unknown.
      *
-     * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
+     * Sustained Performance Mode: Enable/Disables Sustained Performance Mode.
+     *
+     * These must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
      */
     public static final int POWER_HINT_INTERACTION = 2;
+    public static final int POWER_HINT_SUSTAINED_PERFORMANCE_MODE = 6;
 
     public static String wakefulnessToString(int wakefulness) {
         switch (wakefulness) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6b60f47..d80d4be 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6043,6 +6043,33 @@
         public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
 
         /**
+         * Behavior of the display while in VR mode.
+         *
+         * One of {@link #VR_DISPLAY_MODE_LOW_PERSISTENCE} or {@link #VR_DISPLAY_MODE_OFF}.
+         *
+         * @hide
+         */
+        public static final String VR_DISPLAY_MODE = "vr_display_mode";
+
+        /**
+         * Lower the display persistence while the system is in VR mode.
+         *
+         * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE
+         *
+         * @hide.
+         */
+        public static final int VR_DISPLAY_MODE_LOW_PERSISTENCE = 0;
+
+        /**
+         * Do not alter the display persistence while the system is in VR mode.
+         *
+         * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE
+         *
+         * @hide.
+         */
+        public static final int VR_DISPLAY_MODE_OFF = 1;
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f3f0bf..5135657 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1177,6 +1177,15 @@
         return false;
     }
 
+    /* Sets the Sustained Performance requirement for the calling window.
+     * @param enable disables or enables the mode.
+     */
+    public void setSustainedPerformanceMode(boolean enable) {
+        setPrivateFlags(enable
+                ? WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE : 0,
+                WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE);
+    }
+
     private boolean isOutOfBounds(Context context, MotionEvent event) {
         final int x = (int) event.getX();
         final int y = (int) event.getY();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 89e146b..54e9942 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1247,6 +1247,13 @@
         public static final int PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND = 0x00020000;
 
         /**
+         * Flag to indicate that this window needs Sustained Performance Mode if
+         * the device supports it.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00020000;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index e4588fe..da44ca6 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -42,6 +42,7 @@
     private final IMidiManager mMidiManager;
     private final IBinder mClientToken;
     private final IBinder mDeviceToken;
+    private boolean mIsDeviceClosed;
 
     private final CloseGuard mGuard = CloseGuard.get();
 
@@ -123,6 +124,9 @@
      *         or null in case of failure.
      */
     public MidiInputPort openInputPort(int portNumber) {
+        if (mIsDeviceClosed) {
+            return null;
+        }
         try {
             IBinder token = new Binder();
             ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
@@ -146,6 +150,9 @@
      *         or null in case of failure.
      */
     public MidiOutputPort openOutputPort(int portNumber) {
+        if (mIsDeviceClosed) {
+            return null;
+        }
         try {
             IBinder token = new Binder();
             ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
@@ -175,12 +182,15 @@
         if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
             throw new IllegalArgumentException("outputPortNumber out of range");
         }
+        if (mIsDeviceClosed) {
+            return null;
+        }
 
         ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
         if (pfd == null) {
             return null;
         }
-         try {
+        try {
             IBinder token = new Binder();
             int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
             // If the service is a different Process then it will duplicate the pfd
@@ -202,11 +212,14 @@
     @Override
     public void close() throws IOException {
         synchronized (mGuard) {
-            mGuard.close();
-            try {
-                mMidiManager.closeDevice(mClientToken, mDeviceToken);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in closeDevice");
+            if (!mIsDeviceClosed) {
+                mGuard.close();
+                mIsDeviceClosed = true;
+                try {
+                    mMidiManager.closeDevice(mClientToken, mDeviceToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in closeDevice");
+                }
             }
         }
     }
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index e1424f0..f60a3b6 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -63,6 +63,7 @@
             android:id="@+id/importance_buttons"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_marginStart="-6dp"
             android:paddingTop="4dp"
             android:paddingEnd="8dp" >
         <RadioButton
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index baec8ef..d3f2a25 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -29,15 +29,10 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingBottom="8dp"
-        android:paddingStart="8dp">
+        android:paddingStart="8dp"
+        android:animateLayoutChanges="true" >
 
         <!-- volume rows added and removed here! :-) -->
-        <LinearLayout
-                android:id="@+id/volume_row_container"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="@dimen/volume_button_size"
-                android:orientation="vertical"/>
 
         <include layout="@layout/volume_zen_footer" />
 
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 57bac41..f0ae1c9 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -18,7 +18,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:clipChildren="false"
-    android:id="@+id/volume_dialog_row" >
+    android:id="@+id/volume_dialog_row"
+    android:paddingEnd="@dimen/volume_button_size" >
 
     <TextView
         android:id="@+id/volume_row_header"
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index aeb484f..5e8162e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -350,7 +350,7 @@
     </style>
 
     <style name="TextAppearance.NotificationGuts.Radio">
-        <item name="android:alpha">.87</item>
+        <item name="android:alpha">.54</item>
     </style>
 
     <style name="TextAppearance.NotificationGuts.Button">
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 91a8493..de70139 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -100,7 +100,6 @@
     private CustomDialog mDialog;
     private ViewGroup mDialogView;
     private ViewGroup mDialogContentView;
-    private ViewGroup mVolumeRowContainer;
     private ImageButton mExpandButton;
     private final List<VolumeRow> mRows = new ArrayList<>();
     private final SpTexts mSpTexts;
@@ -207,8 +206,6 @@
             }
         });
         mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
-        mVolumeRowContainer =
-                (ViewGroup) mDialogContentView.findViewById(R.id.volume_row_container);
         mExpanded = false;
         mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
         mExpandButton.setOnClickListener(mClickExpand);
@@ -309,7 +306,7 @@
         if (!mRows.isEmpty()) {
             addSpacer(row);
         }
-        mVolumeRowContainer.addView(row.view);
+        mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
         mRows.add(row);
     }
 
@@ -321,7 +318,7 @@
             if (i > 0) {
                 addSpacer(row);
             }
-            mVolumeRowContainer.addView(row.view);
+            mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
         }
     }
 
@@ -332,7 +329,7 @@
                 .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
         final LinearLayout.LayoutParams lp =
                 new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
-        mVolumeRowContainer.addView(v, lp);
+        mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
         row.space = v;
     }
 
@@ -613,8 +610,8 @@
             if (row.ss == null || !row.ss.dynamic) continue;
             if (!mDynamic.get(row.stream)) {
                 mRows.remove(i);
-                mVolumeRowContainer.removeView(row.view);
-                mVolumeRowContainer.removeView(row.space);
+                mDialogContentView.removeView(row.view);
+                mDialogContentView.removeView(row.space);
             }
         }
     }
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 45b6d3e..8163b79 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -38,7 +38,7 @@
     protected static final boolean DEBUG = FingerprintService.DEBUG;
     private IBinder mToken;
     private IFingerprintServiceReceiver mReceiver;
-    private int mCallingUserId;
+    private int mTargetUserId;
     private int mGroupId;
     private boolean mIsRestricted; // True if client does not have MANAGE_FINGERPRINT permission
     private String mOwner;
@@ -50,20 +50,20 @@
      * @param halDeviceId the HAL device ID of the associated fingerprint hardware
      * @param token a unique token for the client
      * @param receiver recipient of related events (e.g. authentication)
-     * @param callingUserId user id of calling user
+     * @param userId target user id for operation
      * @param groupId groupId for the fingerprint set
      * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
      * permission
      * @param owner name of the client that owns this
      */
     public ClientMonitor(Context context, long halDeviceId, IBinder token,
-            IFingerprintServiceReceiver receiver, int callingUserId, int groupId,boolean restricted,
+            IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
             String owner) {
         mContext = context;
         mHalDeviceId = halDeviceId;
         mToken = token;
         mReceiver = receiver;
-        mCallingUserId = callingUserId;
+        mTargetUserId = userId;
         mGroupId = groupId;
         mIsRestricted = restricted;
         mOwner = owner;
@@ -197,8 +197,8 @@
         return mIsRestricted;
     }
 
-    public final int getCallingUserId() {
-        return mCallingUserId;
+    public final int getTargetUserId() {
+        return mTargetUserId;
     }
 
     public final int getGroupId() {
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index e826fee..52dbd5d 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -41,7 +41,7 @@
         try {
             final int result = daemon.enumerate();
             if (result != 0) {
-                Slog.w(TAG, "start enumerate for user " + getCallingUserId()
+                Slog.w(TAG, "start enumerate for user " + getTargetUserId()
                     + " failed, result=" + result);
                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
                 return result;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index fcf7bf5..9a2db8e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -356,7 +356,7 @@
         }
     }
 
-    void startRemove(IBinder token, int fingerId, int callingUserId, int groupId,
+    void startRemove(IBinder token, int fingerId, int groupId, int userId,
             IFingerprintServiceReceiver receiver, boolean restricted) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
         if (daemon == null) {
@@ -364,7 +364,7 @@
             return;
         }
         RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
-                receiver, callingUserId, groupId, fingerId, restricted, token.toString()) {
+                receiver, fingerId, groupId, userId, restricted, token.toString()) {
             @Override
             public void notifyUserActivity() {
                 FingerprintService.this.userActivity();
@@ -794,14 +794,13 @@
 
         @Override // Binder call
         public void remove(final IBinder token, final int fingerId, final int groupId,
-                final IFingerprintServiceReceiver receiver) {
+                final int userId, final IFingerprintServiceReceiver receiver) {
             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
             final boolean restricted = isRestricted();
-            final int callingUserId = UserHandle.getCallingUserId();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    startRemove(token, fingerId, callingUserId, groupId, receiver, restricted);
+                    startRemove(token, fingerId, groupId, userId, receiver, restricted);
                 }
             });
 
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index ffa3c3f..bcf2264 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -30,14 +30,12 @@
  */
 public abstract class RemovalClient extends ClientMonitor {
     private int mFingerId;
-    private int mUserIdForRemove;
 
     public RemovalClient(Context context, long halDeviceId, IBinder token,
-            IFingerprintServiceReceiver receiver, int userId, int groupId, int fingerId,
+            IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId,
             boolean restricted, String owner) {
         super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
         mFingerId = fingerId;
-        mUserIdForRemove = userId;
     }
 
     @Override
@@ -72,25 +70,21 @@
      */
     private boolean sendRemoved(int fingerId, int groupId) {
         IFingerprintServiceReceiver receiver = getReceiver();
-        if (receiver == null)
-            return true; // client not listening
         try {
-            receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
-            return fingerId == 0;
+            if (receiver != null) {
+                receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+            }
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to notify Removed:", e);
         }
-        return false;
+        return fingerId == 0;
     }
 
     @Override
     public boolean onRemoved(int fingerId, int groupId) {
         if (fingerId != 0) {
-            if (fingerId != mFingerId)
             FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
-                    mUserIdForRemove);
-        } else {
-            mUserIdForRemove = UserHandle.USER_NULL;
+                    getTargetUserId());
         }
         return sendRemoved(fingerId, getGroupId());
     }
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 5953dde..07048a4 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -17,16 +17,16 @@
 package com.android.server.lights;
 
 import com.android.server.SystemService;
-import com.android.server.vr.VrManagerInternal;
 import com.android.server.vr.VrManagerService;
-import com.android.server.vr.VrStateListener;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.util.Slog;
@@ -36,6 +36,7 @@
     static final boolean DEBUG = false;
 
     final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+    private boolean mVrModeEnabled;
 
     private final class LightImpl extends Light {
 
@@ -179,17 +180,34 @@
         }
     }
 
+    private int getVrDisplayMode() {
+        int currentUser = ActivityManager.getCurrentUser();
+        return Settings.Secure.getIntForUser(getContext().getContentResolver(),
+                Settings.Secure.VR_DISPLAY_MODE,
+                /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE,
+                currentUser);
+    }
+
     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
         @Override
         public void onVrStateChanged(boolean enabled) throws RemoteException {
             LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
-            if (enabled) {
-                if (DEBUG) Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
-                l.enableLowPersistence();
+            int vrDisplayMode = getVrDisplayMode();
 
+            // User leaves VR mode before altering display settings.
+            if (enabled && vrDisplayMode == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE) {
+                if (!mVrModeEnabled) {
+                    if (DEBUG)
+                        Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
+                    l.enableLowPersistence();
+                    mVrModeEnabled = true;
+                }
             } else {
-                if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
-                l.disableLowPersistence();
+                if (mVrModeEnabled) {
+                    if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
+                    l.disableLowPersistence();
+                    mVrModeEnabled = false;
+                }
             }
         }
     };
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8cd536d..12a2d2e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -143,7 +143,6 @@
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
     private static final int WAKE_LOCK_DRAW = 1 << 7;
-    private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -162,7 +161,6 @@
 
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_LOW_POWER = 5;
-    private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
     private static final int POWER_HINT_VR_MODE = 7;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -470,9 +468,6 @@
     // True if we are currently in light device idle mode.
     private boolean mLightDeviceIdleMode;
 
-    // True if we are currently in sustained performance mode.
-    private boolean mSustainedPerformanceMode;
-
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
@@ -481,8 +476,6 @@
 
     private final SparseIntArray mUidState = new SparseIntArray();
 
-    private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
-
     // True if theater mode is enabled
     private boolean mTheaterModeEnabled;
 
@@ -879,12 +872,6 @@
                     throw new IllegalArgumentException("Wake lock is already dead.");
                 }
                 mWakeLocks.add(wakeLock);
-
-                if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                        == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
-                    int numberWakelock = mSustainedPerformanceUid.get(uid);
-                    mSustainedPerformanceUid.put(uid, numberWakelock + 1);
-                }
                 setWakeLockDisabledStateLocked(wakeLock);
                 notifyAcquire = true;
             }
@@ -953,17 +940,6 @@
                 mRequestWaitForNegativeProximity = true;
             }
 
-
-            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
-                int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
-                if (numberWakelock == 1) {
-                    mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
-                } else {
-                    mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
-                }
-            }
-
             wakeLock.mLock.unlinkToDeath(wakeLock, 0);
             removeWakeLockLocked(wakeLock, index);
         }
@@ -1586,10 +1562,6 @@
                         break;
                     case PowerManager.DRAW_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DRAW;
-                    case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
-                        if (!wakeLock.mDisabled) {
-                            mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
-                        }
                         break;
                 }
             }
@@ -2288,14 +2260,6 @@
         if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
             setHalAutoSuspendModeLocked(true);
         }
-
-        if (mSustainedPerformanceMode
-                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
-            setSustainedPerformanceModeLocked(false);
-        } else if (!mSustainedPerformanceMode
-                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
-            setSustainedPerformanceModeLocked(true);
-        }
     }
 
     /**
@@ -2394,12 +2358,6 @@
         }
     }
 
-    private void setSustainedPerformanceModeLocked(boolean mode) {
-            mSustainedPerformanceMode = mode;
-            powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
-                              mSustainedPerformanceMode ? 1 : 0);
-    }
-
     boolean isDeviceIdleModeInternal() {
         synchronized (mLock) {
             return mDeviceIdleMode;
@@ -2531,7 +2489,7 @@
     void updateUidProcStateInternal(int uid, int procState) {
         synchronized (mLock) {
             mUidState.put(uid, procState);
-            if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
+            if (mDeviceIdleMode) {
                 updateWakeLockDisabledStatesLocked();
             }
         }
@@ -2552,9 +2510,7 @@
         for (int i = 0; i < numWakeLocks; i++) {
             final WakeLock wakeLock = mWakeLocks.get(i);
             if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.PARTIAL_WAKE_LOCK
-                    || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                    == PowerManager.PARTIAL_WAKE_LOCK) {
                 if (setWakeLockDisabledStateLocked(wakeLock)) {
                     changed = true;
                     if (wakeLock.mDisabled) {
@@ -2573,9 +2529,9 @@
     }
 
     private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
-        boolean disabled = false;
         if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                 == PowerManager.PARTIAL_WAKE_LOCK) {
+            boolean disabled = false;
             if (mDeviceIdleMode) {
                 final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
                 // If we are in idle mode, we will ignore all partial wake locks that are
@@ -2589,16 +2545,10 @@
                     disabled = true;
                 }
             }
-        } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
-                && mUidState.get(wakeLock.mOwnerUid,
-                                 ActivityManager.PROCESS_STATE_CACHED_EMPTY)
-                > ActivityManager.PROCESS_STATE_TOP) {
-            disabled = true;
-        }
-        if (wakeLock.mDisabled != disabled) {
-            wakeLock.mDisabled = disabled;
-            return true;
+            if (wakeLock.mDisabled != disabled) {
+                wakeLock.mDisabled = disabled;
+                return true;
+            }
         }
         return false;
     }
@@ -2806,7 +2756,6 @@
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
-            pw.println("  mSustainedPerformanceMode=" + mSustainedPerformanceMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2921,14 +2870,6 @@
             pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
-            pw.println();
-            pw.println("Sustained Performance UIDs:");
-            for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
-                pw.print("  UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
-                pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
-            }
-
-
             wcd = mWirelessChargerDetector;
         }
 
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 30442bc..e13ee13 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -161,8 +161,10 @@
         PackageMonitor monitor = new PackageMonitor() {
             private void buildTvInputList(String[] packages) {
                 synchronized (mLock) {
-                    buildTvInputListLocked(getChangingUserId(), packages);
-                    buildTvContentRatingSystemListLocked(getChangingUserId());
+                    if (mCurrentUserId == getChangingUserId()) {
+                        buildTvInputListLocked(mCurrentUserId, packages);
+                        buildTvContentRatingSystemListLocked(mCurrentUserId);
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 30194bf..249a076 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -212,7 +212,7 @@
         if (userManager == null) {
             return null;
         }
-        return userManager.getProfileIdsWithDisabled(ActivityManager.getCurrentUser());
+        return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser());
     }
 
     public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
diff --git a/services/core/java/com/android/server/vr/SettingsObserver.java b/services/core/java/com/android/server/vr/SettingsObserver.java
index ce76863..3d1227d 100644
--- a/services/core/java/com/android/server/vr/SettingsObserver.java
+++ b/services/core/java/com/android/server/vr/SettingsObserver.java
@@ -38,7 +38,7 @@
 public class SettingsObserver {
 
     private final String mSecureSettingName;
-    private final BroadcastReceiver mSettingRestorReceiver;
+    private final BroadcastReceiver mSettingRestoreReceiver;
     private final ContentObserver mContentObserver;
     private final Set<SettingChangeListener> mSettingsListeners = new ArraySet<>();
 
@@ -67,7 +67,7 @@
             @NonNull final Uri settingUri, @NonNull final String secureSettingName) {
 
         mSecureSettingName = secureSettingName;
-        mSettingRestorReceiver = new BroadcastReceiver() {
+        mSettingRestoreReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
@@ -117,7 +117,6 @@
      */
     public void addListener(@NonNull SettingChangeListener listener) {
         mSettingsListeners.add(listener);
-
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b90d0d1..8a003de 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -116,6 +116,11 @@
     private boolean mAnimatingForIme;
     private boolean mAdjustedForIme;
     private WindowState mDelayedImeWin;
+    private boolean mAdjustedForDivider;
+    private float mDividerAnimationStart;
+    private float mDividerAnimationTarget;
+    private float mLastAnimationProgress;
+    private float mLastDividerProgress;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -208,16 +213,18 @@
         return mLastVisibility;
     }
 
-    void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
-        if (mAdjustedForIme != adjusted) {
-            mAdjustedForIme = adjusted;
+    void setAdjustedForIme(
+            boolean adjustedForIme, boolean adjustedForDivider,
+            boolean animate, WindowState imeWin) {
+        if (mAdjustedForIme != adjustedForIme || mAdjustedForDivider != adjustedForDivider) {
             if (animate) {
-                startImeAdjustAnimation(adjusted, imeWin);
+                startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
             } else {
-
                 // Animation might be delayed, so only notify if we don't run an animation.
-                notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
+                notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
             }
+            mAdjustedForIme = adjustedForIme;
+            mAdjustedForDivider = adjustedForDivider;
         }
     }
 
@@ -457,11 +464,25 @@
         mAnimationTarget = to;
     }
 
-    private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
+    private void startImeAdjustAnimation(
+            boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
         mAnimatingForIme = true;
         mAnimationStarted = false;
-        mAnimationStart = adjusted ? 0 : 1;
-        mAnimationTarget = adjusted ? 1 : 0;
+
+        // If we're not in an animation, the starting point depends on whether we're adjusted
+        // or not. If we're already in an animation, we start from where the current animation
+        // left off, so that the motion doesn't look discontinuous.
+        if (!mAnimatingForIme) {
+            mAnimationStart = mAdjustedForIme ? 1 : 0;
+            mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
+            mLastAnimationProgress = mAnimationStart;
+            mLastDividerProgress = mDividerAnimationStart;
+        } else {
+            mAnimationStart = mLastAnimationProgress;
+            mDividerAnimationStart = mLastDividerProgress;
+        }
+        mAnimationTarget = adjustedForIme ? 1 : 0;
+        mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
 
         final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
         for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -492,10 +513,12 @@
                 if (mDelayedImeWin != null) {
                     mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
                 }
-                notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+                notifyAdjustedForImeChanged(
+                        adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
             };
         } else {
-            notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+            notifyAdjustedForImeChanged(
+                    adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
         }
     }
 
@@ -539,11 +562,15 @@
         for (int i = stacks.size() - 1; i >= 0; --i) {
             final TaskStack stack = stacks.get(i);
             if (stack != null && stack.isAdjustedForIme()) {
-                if (t >= 1f && mAnimationTarget == 0f) {
+                if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
                     stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                     updated = true;
                 } else {
-                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+                    mLastAnimationProgress = getInterpolatedAnimationValue(t);
+                    mLastDividerProgress = getInterpolatedDividerValue(t);
+                    updated |= stack.updateAdjustForIme(
+                            mLastAnimationProgress,
+                            mLastDividerProgress,
                             false /* force */);
                 }
                 if (t >= 1f) {
@@ -555,6 +582,8 @@
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
         if (t >= 1.0f) {
+            mLastAnimationProgress = mAnimationTarget;
+            mLastDividerProgress = mDividerAnimationTarget;
             mAnimatingForIme = false;
             return false;
         } else {
@@ -596,6 +625,10 @@
         return t * mAnimationTarget + (1 - t) * mAnimationStart;
     }
 
+    private float getInterpolatedDividerValue(float t) {
+        return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
+    }
+
     /**
      * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
      */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1fd2b1f..a289855 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -126,6 +126,7 @@
     private WindowState mImeWin;
     private float mMinimizeAmount;
     private float mAdjustImeAmount;
+    private float mAdjustDividerAmount;
     private final int mDockedStackMinimizeThickness;
 
     // If this is true, we are in the bounds animating mode.
@@ -853,7 +854,8 @@
         if (!mAdjustedForIme) {
             mAdjustedForIme = true;
             mAdjustImeAmount = 0f;
-            updateAdjustForIme(0f, true /* force */);
+            mAdjustDividerAmount = 0f;
+            updateAdjustForIme(0f, 0f, true /* force */);
         }
     }
 
@@ -873,9 +875,11 @@
      *
      * @return true if a traversal should be performed after the adjustment.
      */
-    boolean updateAdjustForIme(float adjustAmount, boolean force) {
-        if (adjustAmount != mAdjustImeAmount || force) {
+    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
+        if (adjustAmount != mAdjustImeAmount
+                || adjustDividerAmount != mAdjustDividerAmount || force) {
             mAdjustImeAmount = adjustAmount;
+            mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
             return isVisibleForUserLocked();
         } else {
@@ -895,6 +899,7 @@
             mAdjustedForIme = false;
             mImeGoingAway = false;
             mAdjustImeAmount = 0f;
+            mAdjustDividerAmount = 0f;
             updateAdjustedBounds();
             mService.setResizeDimLayer(false, mStackId, 1.0f);
         } else {
@@ -992,25 +997,27 @@
                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
             mFullyAdjustedImeBounds.set(mBounds);
         } else {
-            final int top;
-            final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-            if (isFocusedStack) {
-                // If this stack is docked on bottom and has focus, we shift it up so that it's not
-                // occluded by IME. We try to move it up by the height of the IME window, but only
-                // to the extent that leaves at least 30% of the top stack visible.
-                final int minTopStackBottom =
-                        getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
-                top = Math.max(
-                        mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
-            } else {
-                // If this stack is docked on bottom but doesn't have focus, we don't need to adjust
-                // for IME, but still need to apply a small adjustment due to the thinner divider.
-                top = mBounds.top - dividerWidth + dividerWidthInactive;
-            }
+            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
+            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
+
+            // When the stack is on bottom and has focus, it needs to be moved up so as to
+            // not occluded by IME, and at the same time adjusted for divider width.
+            // We try to move it up by the height of the IME window, but only to the extent
+            // that leaves at least 30% of the top stack visible.
+            // 'top' is where the top of bottom stack will move to in this case.
+            final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
+            final int minTopStackBottom =
+                    getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
+            final int top = Math.max(
+                    mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
 
             mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.top =
-                    (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top);
+            // Account for the adjustment for IME and divider width separately.
+            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
+            // and dividerWidthDelta is due to divider width change only.
+            mTmpAdjustedBounds.top = mBounds.top +
+                    (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
+                            mAdjustDividerAmount * dividerWidthDelta);
             mFullyAdjustedImeBounds.set(mBounds);
             mFullyAdjustedImeBounds.top = top;
             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
@@ -1082,9 +1089,10 @@
         }
         setAdjustedBounds(mTmpAdjustedBounds);
 
-        final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-        if (mAdjustedForIme && adjust && !isFocusedStack) {
-            final float alpha = mAdjustImeAmount * IME_ADJUST_DIM_AMOUNT;
+        final boolean isImeTarget = (mService.getImeTargetStackLocked() == this);
+        if (mAdjustedForIme && adjust && !isImeTarget) {
+            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
+                    * IME_ADJUST_DIM_AMOUNT;
             mService.setResizeDimLayer(true, mStackId, alpha);
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 38f12a1..9994af3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7455,27 +7455,38 @@
 
     void adjustForImeIfNeeded(final DisplayContent displayContent) {
         final WindowState imeWin = mInputMethodWindow;
-        final TaskStack focusedStack = getFocusedStackLocked();
+        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw();
         final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
-        if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
-                && dockVisible && focusedStack != null) {
-            final boolean isFocusOnBottom = focusedStack.getDockSide() == DOCKED_BOTTOM;
+        final TaskStack imeTargetStack = getImeTargetStackLocked();
+
+        // The divider could be adjusted for IME position, or be thinner than usual,
+        // or both. There are three possible cases:
+        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
+        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
+        // - If IME is not visible, divider is not moved and is normal width.
+
+        if (imeVisible && dockVisible && imeTargetStack != null) {
+            final boolean isFocusOnBottom = imeTargetStack.getDockSide() == DOCKED_BOTTOM;
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
                 if (stack.isVisibleLocked() && (isFocusOnBottom || isDockedOnBottom)) {
                     stack.setAdjustedForIme(imeWin);
+                } else {
+                    stack.resetAdjustedForIme(false);
                 }
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    isFocusOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin);
         } else {
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 stack.resetAdjustedForIme(!dockVisible);
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, null);
         }
     }
 
@@ -7608,8 +7619,10 @@
         return mCurrentFocus;
     }
 
-    TaskStack getFocusedStackLocked() {
-        return mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+    TaskStack getImeTargetStackLocked() {
+        // Don't use WindowState.getStack() because it returns home stack for system windows.
+        Task imeTask = mInputMethodTarget != null ? mInputMethodTarget.getTask() : null;
+        return imeTask != null ? imeTask.mStack : null;
     }
 
     private void showAuditSafeModeNotification() {
@@ -9354,7 +9367,6 @@
         WindowState newFocus = computeFocusedWindowLocked();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
-            TaskStack oldFocusedStack = getFocusedStackLocked();
             // This check makes sure that we don't already have the focus
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -9376,7 +9388,6 @@
             mLosingFocus.remove(newFocus);
 
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
-            TaskStack newFocusedStack = getFocusedStackLocked();
 
             if (imWindowChanged && oldFocus != mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
@@ -9406,18 +9417,6 @@
                 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
             }
 
-            // TODO: Reset and re-apply IME adjustment if needed when stack focus changed.
-            // This makes sure divider starts an animation from pre-adjust position to final
-            // position. Ideally we want to skip the reset and animation from current position
-            // directly to final position.
-            final WindowState imeWin = mInputMethodWindow;
-            if (oldFocusedStack != null) {
-                oldFocusedStack.resetAdjustedForIme(true);
-            }
-            if (newFocusedStack != null) {
-                newFocusedStack.resetAdjustedForIme(true);
-            }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, false, imeWin);
             adjustForImeIfNeeded(displayContent);
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 1e6c585..928fcc0 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -8,6 +8,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
@@ -128,6 +129,9 @@
     private boolean mTraversalScheduled;
     private int mDeferDepth = 0;
 
+    private boolean mSustainedPerformanceModeEnabled = false;
+    private boolean mSustainedPerformanceModeCurrent = false;
+
     private static final class LayerAndToken {
         public int layer;
         public AppWindowToken token;
@@ -288,7 +292,7 @@
         mButtonBrightness = -1;
         mUserActivityTimeout = -1;
         mObscureApplicationContentOnSecondaryDisplays = false;
-
+        mSustainedPerformanceModeCurrent = false;
         mService.mTransactionSequence++;
 
         final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
@@ -487,6 +491,13 @@
                     mUserActivityTimeout);
         }
 
+        if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
+            mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
+            mService.mPowerManagerInternal.powerHint(
+                    mService.mPowerManagerInternal.POWER_HINT_SUSTAINED_PERFORMANCE_MODE,
+                    (mSustainedPerformanceModeEnabled ? 1 : 0));
+        }
+
         if (mService.mTurnOnScreen) {
             if (mService.mAllowTheaterModeWakeFromLayout
                     || Settings.Global.getInt(mService.mContext.getContentResolver(),
@@ -1409,6 +1420,7 @@
         final LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
+        final int privateflags = attrs.privateFlags;
 
         if (canBeSeen && w.isObscuringFullscreen(dispInfo)) {
             // This window completely covers everything behind it,
@@ -1469,6 +1481,9 @@
                         && w.mAttrs.preferredDisplayModeId != 0) {
                     mPreferredModeId = w.mAttrs.preferredDisplayModeId;
                 }
+                if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
+                    mSustainedPerformanceModeCurrent = true;
+                }
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 4468857..ef9739d 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -32,6 +32,7 @@
 import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.UserInfo;
+import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
@@ -64,15 +65,14 @@
         Context realTestContext = getContext();
         Context mockContext = new MyMockContext(realTestContext);
         setContext(mockContext);
-        mAms = new MyAccountManagerService(getContext(),
-                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realTestContext);
+        mAms = createAccountManagerService(mockContext, realTestContext);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)).delete();
-        new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)).delete();
-        new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)).delete();
+        SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
+        SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
+        SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
         super.tearDown();
     }
 
@@ -88,7 +88,7 @@
     }
 
     public void testCheckAddAccount() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a21 = new Account("account2", "type1");
         Account a31 = new Account("account3", "type1");
@@ -129,7 +129,7 @@
     }
 
     public void testPasswords() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
         mAms.addAccountExplicitly(a11, "p11", null);
@@ -145,7 +145,7 @@
     }
 
     public void testUserdata() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Bundle u11 = new Bundle();
         u11.putString("a", "a_a11");
@@ -178,7 +178,7 @@
     }
 
     public void testAuthtokens() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
         mAms.addAccountExplicitly(a11, "p11", null);
@@ -211,10 +211,89 @@
         assertNull(mAms.peekAuthToken(a12, "att2"));
     }
 
-    private void unlockUser(int userId) {
+    public void testRemovedAccountSync() throws Exception {
+        unlockSystemUser();
+        Account a1 = new Account("account1", "type1");
+        Account a2 = new Account("account2", "type2");
+        mAms.addAccountExplicitly(a1, "p1", null);
+        mAms.addAccountExplicitly(a2, "p2", null);
+
+        Context originalContext = ((MyMockContext)getContext()).mTestContext;
+        // create a separate instance of AMS. It initially assumes that user0 is locked
+        AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext);
+
+        // Verify that account can be removed when user is locked
+        ams2.removeAccountInternal(a1);
+        Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+        assertEquals(1, accounts.length);
+        assertEquals("Only a2 should be returned", a2, accounts[0]);
+
+        // Verify that CE db file is unchanged and still has 2 accounts
+        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+        assertEquals("CE database should still have 2 accounts", 2, accountsNumber);
+
+        // Unlock the user and verify that db has been updated
+        ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+        accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+        assertEquals("CE database should now have 1 account", 2, accountsNumber);
+        accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+        assertEquals(1, accounts.length);
+        assertEquals("Only a2 should be returned", a2, accounts[0]);
+    }
+
+    public void testPreNDatabaseMigration() throws Exception {
+        String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
+        Context originalContext = ((MyMockContext) getContext()).mTestContext;
+        PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName);
+        // Assert that database was created with 1 account
+        int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName);
+        assertEquals("pre-N database should have 1 account", 1, n);
+
+        // Start testing
+        unlockSystemUser();
+        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+        assertEquals("1 account should be migrated", 1, accounts.length);
+        assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
+        assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0]));
+        assertEquals("Authtoken should be migrated",
+                PreNTestDatabaseHelper.TOKEN_STRING,
+                mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE));
+
+        assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName,
+                new File(preNDatabaseName).exists());
+
+        // Verify that ce/de files are present
+        String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM);
+        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        assertTrue("DE database file should be created at " + deDatabaseName,
+                new File(deDatabaseName).exists());
+        assertTrue("CE database file should be created at " + ceDatabaseName,
+                new File(ceDatabaseName).exists());
+    }
+
+    private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
+        SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
+        try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
+            assertTrue(cursor.moveToNext());
+            return cursor.getInt(0);
+        }
+    }
+
+    private AccountManagerService createAccountManagerService(Context mockContext,
+            Context realContext) {
+        return new MyAccountManagerService(mockContext,
+                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
+    }
+
+    private void unlockSystemUser() {
+        mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+    }
+
+    private static Intent newIntentForUser(int userId) {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        mAms.onUserUnlocked(intent);
+        return intent;
     }
 
     static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
@@ -264,11 +343,13 @@
         private Context mTestContext;
         private AppOpsManager mAppOpsManager;
         private UserManager mUserManager;
+        private PackageManager mPackageManager;
 
         public MyMockContext(Context testContext) {
             this.mTestContext = testContext;
             this.mAppOpsManager = mock(AppOpsManager.class);
             this.mUserManager = mock(UserManager.class);
+            this.mPackageManager = mock(PackageManager.class);
             final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
             when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
         }
@@ -279,6 +360,11 @@
         }
 
         @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        @Override
         public Object getSystemService(String name) {
             if (Context.APP_OPS_SERVICE.equals(name)) {
                 return mAppOpsManager;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
new file mode 100644
index 0000000..97adbe6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.accounts;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Helper class for emulating pre-N database
+ */
+class PreNTestDatabaseHelper extends SQLiteOpenHelper {
+
+    public static final String TOKEN_STRING = "token-string-123";
+    public static final String ACCOUNT_TYPE = "type1";
+    public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
+    public static final String ACCOUNT_PASSWORD = "Password";
+    public static final String TOKEN_TYPE = "SID";
+
+    public PreNTestDatabaseHelper(Context context, String name) {
+        super(context, name, null, 4);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE accounts ( "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                + "name TEXT NOT NULL, "
+                + "type TEXT NOT NULL, "
+                + "password TEXT, "
+                + "UNIQUE(name, type))");
+        db.execSQL("INSERT INTO accounts (name, type, password) VALUES "
+                + "('" + ACCOUNT_NAME + "', '" + ACCOUNT_TYPE + "', '" + ACCOUNT_PASSWORD + "')");
+
+        db.execSQL("CREATE TABLE authtokens (  "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                + "accounts_id INTEGER NOT NULL, "
+                + "type TEXT NOT NULL,  "
+                + "authtoken TEXT, "
+                + "UNIQUE (accounts_id, type ))");
+        db.execSQL("INSERT INTO authtokens (accounts_id, type, authtoken) VALUES "
+                + "(1, '" + TOKEN_TYPE + "', '" + TOKEN_STRING + "')");
+
+        db.execSQL("CREATE TABLE grants (  "
+                + "accounts_id INTEGER NOT NULL, "
+                + "auth_token_type STRING NOT NULL,  "
+                + "uid INTEGER NOT NULL,  "
+                + "UNIQUE (accounts_id,auth_token_type,uid))");
+
+        db.execSQL("CREATE TABLE extras ( "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                + "accounts_id INTEGER, "
+                + "key TEXT NOT NULL, "
+                + "value TEXT, "
+                + "UNIQUE(accounts_id , key))");
+
+        db.execSQL("CREATE TABLE meta ( "
+                + "key TEXT PRIMARY KEY NOT NULL, "
+                + "value TEXT)");
+
+        db.execSQL(""
+                + " CREATE TRIGGER accountsDelete DELETE ON accounts "
+                + " BEGIN"
+                + "   DELETE FROM authtokens"
+                + "     WHERE accounts_id=OLD._id;"
+                + "   DELETE FROM extras"
+                + "     WHERE accounts_id=OLD._id;"
+                + "   DELETE FROM grants"
+                + "     WHERE accounts_id=OLD._id;"
+                + " END");
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        throw new UnsupportedOperationException("Upgrade of test database is not supported");
+    }
+
+    public static void createV4Database(Context context, String name) {
+        PreNTestDatabaseHelper helper = new PreNTestDatabaseHelper(context, name);
+        helper.getWritableDatabase();
+        helper.close();
+    }
+
+}