Merge "Rebind backup transports only when clearly needed" into mnc-dev
diff --git a/Android.mk b/Android.mk
index eb6e7b5..146afe0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -84,6 +84,7 @@
 	core/java/android/app/job/IJobScheduler.aidl \
 	core/java/android/app/job/IJobService.aidl \
 	core/java/android/app/ITransientNotification.aidl \
+	core/java/android/app/IUidObserver.aidl \
 	core/java/android/app/IUiAutomationConnection.aidl \
 	core/java/android/app/IUiModeManager.aidl \
 	core/java/android/app/IUserSwitchObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index 50147d8..80c4dc8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7160,6 +7160,7 @@
   public static final class ScanSettings.Builder {
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
+    method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
     method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
@@ -28891,7 +28892,6 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
-    field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
   public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
@@ -28917,7 +28917,6 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
-    method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -30325,6 +30324,7 @@
     method public android.net.Uri getSubscriptionAddress();
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
+    method public boolean isEnabled();
     method public boolean supportsUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
@@ -34445,6 +34445,8 @@
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
     method public void setType(int);
+    method public void snooze(int);
+    field public static final int SNOOZE_TIME_DEFAULT;
     field public static final int TYPE_FLOATING = 1; // 0x1
     field public static final int TYPE_PRIMARY = 0; // 0x0
   }
@@ -36509,6 +36511,7 @@
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
+    method public static int getDefaultActionModeSnoozeTime();
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
@@ -36912,6 +36915,7 @@
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
+    method public abstract void setTextStyle(int, int, int, int);
     method public abstract void setVisibility(int);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 26466ed..6c4f278 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31021,7 +31021,6 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
-    field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
   public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
@@ -31047,7 +31046,6 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
-    method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -32511,6 +32509,7 @@
     method public android.net.Uri getSubscriptionAddress();
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
+    method public boolean isEnabled();
     method public boolean supportsUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
@@ -32652,6 +32651,7 @@
     method public void cancelMissedCallsNotification();
     method public deprecated void clearAccounts();
     method public void clearPhoneAccounts();
+    method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
     method public boolean endCall();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
@@ -32667,7 +32667,6 @@
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
-    method public java.util.List<android.telecom.PhoneAccountHandle> getRegisteredConnectionManagers();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
     method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
@@ -36708,6 +36707,8 @@
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
     method public void setType(int);
+    method public void snooze(int);
+    field public static final int SNOOZE_TIME_DEFAULT;
     field public static final int TYPE_FLOATING = 1; // 0x1
     field public static final int TYPE_PRIMARY = 0; // 0x0
   }
@@ -38772,6 +38773,7 @@
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
+    method public static int getDefaultActionModeSnoozeTime();
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
@@ -39175,6 +39177,7 @@
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
+    method public abstract void setTextStyle(int, int, int, int);
     method public abstract void setVisibility(int);
   }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 15cfbcd..cdf15e1 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1970,6 +1970,22 @@
             return true;
         }
 
+        case REGISTER_UID_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IUidObserver observer = IUidObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            registerUidObserver(observer);
+            return true;
+        }
+
+        case UNREGISTER_UID_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IUidObserver observer = IUidObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            unregisterUidObserver(observer);
+            return true;
+        }
+
         case GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -5077,6 +5093,28 @@
         reply.recycle();
     }
 
+    public void registerUidObserver(IUidObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void unregisterUidObserver(IUidObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5dcbe37..cb436b5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4585,7 +4585,7 @@
             // crash if we can't get it.
             IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
             try {
-                final ProxyInfo proxyInfo = service.getDefaultProxy();
+                final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                 Proxy.setHttpProxySystemProperty(proxyInfo);
             } catch (RemoteException e) {}
         }
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index a06bc31..b703b0e 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -635,6 +635,15 @@
         }
 
         @Override
+        public void setTextStyle(int size, int fgColor, int bgColor, int style) {
+            ViewNodeText t = getNodeText();
+            t.mTextColor = fgColor;
+            t.mTextBackgroundColor = bgColor;
+            t.mTextSize = size;
+            t.mTextStyle = style;
+        }
+
+        @Override
         public void setHint(CharSequence hint) {
             getNodeText().mHint = hint != null ? hint.toString() : null;
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 4ba1055..310c5ef 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -387,6 +387,9 @@
     public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
     public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
 
+    public void registerUidObserver(IUidObserver observer) throws RemoteException;
+    public void unregisterUidObserver(IUidObserver observer) throws RemoteException;
+
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
 
     public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException;
@@ -844,4 +847,6 @@
     int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295;
     int UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
     int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297;
+    int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298;
+    int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299;
 }
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
new file mode 100644
index 0000000..308cb94
--- /dev/null
+++ b/core/java/android/app/IUidObserver.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 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.app;
+
+/** {@hide} */
+oneway interface IUidObserver {
+    void onUidStateChanged(int uid, int procState);
+    void onUidGone(int uid);
+}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 4f81f98..eb6166a 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -333,19 +333,25 @@
 
     public void setBluetoothTethering(boolean value) {
         if (DBG) log("setBluetoothTethering(" + value + ")");
-        try {
-            mPanService.setBluetoothTethering(value);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+
+        if (mPanService != null && isEnabled()) {
+            try {
+                mPanService.setBluetoothTethering(value);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+            }
         }
     }
 
     public boolean isTetheringOn() {
         if (VDBG) log("isTetheringOn()");
-        try {
-            return mPanService.isTetheringOn();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+
+        if (mPanService != null && isEnabled()) {
+            try {
+                return mPanService.isTetheringOn();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+            }
         }
         return false;
     }
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 4eeb577..d616624 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -249,9 +249,7 @@
          *
          * @param callbackType The callback type flags for the scan.
          * @throws IllegalArgumentException If the {@code callbackType} is invalid.
-         * @hide
          */
-        @SystemApi
         public Builder setCallbackType(int callbackType) {
 
             if (!isValidCallbackType(callbackType)) {
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index 84e9912..933ce0d 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -16,8 +16,13 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.IntDef;
 import android.util.AndroidException;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * <p><code>CameraAccessException</code> is thrown if a camera device could not
  * be queried or opened by the {@link CameraManager}, or if the connection to an
@@ -76,6 +81,16 @@
      */
     public static final int CAMERA_DEPRECATED_HAL = 1000;
 
+     /** @hide */
+     @Retention(RetentionPolicy.SOURCE)
+     @IntDef(
+         {CAMERA_IN_USE,
+          MAX_CAMERAS_IN_USE,
+          CAMERA_DISABLED,
+          CAMERA_DISCONNECTED,
+          CAMERA_ERROR})
+     public @interface AccessError {};
+
     // Make the eclipse warning about serializable exceptions go away
     private static final long serialVersionUID = 5630338637471475675L; // randomly generated
 
@@ -88,26 +103,27 @@
      * @see #CAMERA_DISCONNECTED
      * @see #CAMERA_ERROR
      */
+    @AccessError
     public final int getReason() {
         return mReason;
     }
 
-    public CameraAccessException(int problem) {
+    public CameraAccessException(@AccessError int problem) {
         super(getDefaultMessage(problem));
         mReason = problem;
     }
 
-    public CameraAccessException(int problem, String message) {
+    public CameraAccessException(@AccessError int problem, String message) {
         super(message);
         mReason = problem;
     }
 
-    public CameraAccessException(int problem, String message, Throwable cause) {
+    public CameraAccessException(@AccessError int problem, String message, Throwable cause) {
         super(message, cause);
         mReason = problem;
     }
 
-    public CameraAccessException(int problem, Throwable cause) {
+    public CameraAccessException(@AccessError int problem, Throwable cause) {
         super(getDefaultMessage(problem), cause);
         mReason = problem;
     }
@@ -115,7 +131,7 @@
     /**
      * @hide
      */
-    public static String getDefaultMessage(int problem) {
+    public static String getDefaultMessage(@AccessError int problem) {
         switch (problem) {
             case CAMERA_IN_USE:
                 return "The camera device is in use already";
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index c6f622c..b3e7cfc 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Handler;
 import android.view.Surface;
 
@@ -73,6 +75,7 @@
     /**
      * Get the camera device that this session is created for.
      */
+    @NonNull
     public abstract CameraDevice getDevice();
 
     /**
@@ -133,7 +136,7 @@
      *
      * @see StateCallback#onSurfacePrepared
      */
-    public abstract void prepare(Surface surface) throws CameraAccessException;
+    public abstract void prepare(@NonNull Surface surface) throws CameraAccessException;
 
     /**
      * <p>Submit a request for an image to be captured by the camera device.</p>
@@ -194,7 +197,8 @@
      * @see #abortCaptures
      * @see CameraDevice#createReprocessableCaptureSession
      */
-    public abstract int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
+    public abstract int capture(@NonNull CaptureRequest request,
+            @Nullable CaptureCallback listener, @Nullable Handler handler)
             throws CameraAccessException;
 
     /**
@@ -252,8 +256,9 @@
      * @see #setRepeatingBurst
      * @see #abortCaptures
      */
-    public abstract int captureBurst(List<CaptureRequest> requests, CaptureCallback listener,
-            Handler handler) throws CameraAccessException;
+    public abstract int captureBurst(@NonNull List<CaptureRequest> requests,
+            @Nullable CaptureCallback listener, @Nullable Handler handler)
+            throws CameraAccessException;
 
     /**
      * Request endlessly repeating capture of images by this capture session.
@@ -318,8 +323,9 @@
      * @see #stopRepeating
      * @see #abortCaptures
      */
-    public abstract int setRepeatingRequest(CaptureRequest request, CaptureCallback listener,
-            Handler handler) throws CameraAccessException;
+    public abstract int setRepeatingRequest(@NonNull CaptureRequest request,
+            @Nullable CaptureCallback listener, @Nullable Handler handler)
+            throws CameraAccessException;
 
     /**
      * <p>Request endlessly repeating capture of a sequence of images by this
@@ -389,8 +395,9 @@
      * @see #stopRepeating
      * @see #abortCaptures
      */
-    public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener,
-            Handler handler) throws CameraAccessException;
+    public abstract int setRepeatingBurst(@NonNull List<CaptureRequest> requests,
+            @Nullable CaptureCallback listener, @Nullable Handler handler)
+            throws CameraAccessException;
 
     /**
      * <p>Cancel any ongoing repeating capture set by either
@@ -478,6 +485,7 @@
      * @see android.media.ImageWriter
      * @see android.media.ImageReader
      */
+    @Nullable
     public abstract Surface getInputSurface();
 
     /**
@@ -525,7 +533,7 @@
          *
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          */
-        public abstract void onConfigured(CameraCaptureSession session);
+        public abstract void onConfigured(@NonNull CameraCaptureSession session);
 
         /**
          * This method is called if the session cannot be configured as requested.
@@ -540,7 +548,7 @@
          *
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          */
-        public abstract void onConfigureFailed(CameraCaptureSession session);
+        public abstract void onConfigureFailed(@NonNull CameraCaptureSession session);
 
         /**
          * This method is called every time the session has no more capture requests to process.
@@ -555,7 +563,7 @@
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          *
          */
-        public void onReady(CameraCaptureSession session) {
+        public void onReady(@NonNull CameraCaptureSession session) {
             // default empty implementation
         }
 
@@ -571,7 +579,7 @@
          *
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          */
-        public void onActive(CameraCaptureSession session) {
+        public void onActive(@NonNull CameraCaptureSession session) {
             // default empty implementation
         }
 
@@ -589,7 +597,7 @@
          *
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          */
-        public void onClosed(CameraCaptureSession session) {
+        public void onClosed(@NonNull CameraCaptureSession session) {
             // default empty implementation
         }
 
@@ -608,7 +616,8 @@
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          * @param surface the Surface that was used with the {@link #prepare} call.
          */
-        public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
+        public void onSurfacePrepared(@NonNull CameraCaptureSession session,
+                @NonNull Surface surface) {
             // default empty implementation
         }
     }
@@ -675,8 +684,8 @@
          *
          * @see android.media.MediaActionSound
          */
-        public void onCaptureStarted(CameraCaptureSession session,
-                CaptureRequest request, long timestamp, long frameNumber) {
+        public void onCaptureStarted(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, long timestamp, long frameNumber) {
             // Temporary trampoline for API change transition
             onCaptureStarted(session, request, timestamp);
         }
@@ -756,8 +765,8 @@
          * @see #setRepeatingRequest
          * @see #setRepeatingBurst
          */
-        public void onCaptureProgressed(CameraCaptureSession session,
-                CaptureRequest request, CaptureResult partialResult) {
+        public void onCaptureProgressed(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
             // default empty implementation
         }
 
@@ -785,8 +794,8 @@
          * @see #setRepeatingRequest
          * @see #setRepeatingBurst
          */
-        public void onCaptureCompleted(CameraCaptureSession session,
-                CaptureRequest request, TotalCaptureResult result) {
+        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
             // default empty implementation
         }
 
@@ -814,8 +823,8 @@
          * @see #setRepeatingRequest
          * @see #setRepeatingBurst
          */
-        public void onCaptureFailed(CameraCaptureSession session,
-                CaptureRequest request, CaptureFailure failure) {
+        public void onCaptureFailed(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
             // default empty implementation
         }
 
@@ -844,7 +853,7 @@
          * @see CaptureFailure#getSequenceId()
          * @see #onCaptureSequenceAborted
          */
-        public void onCaptureSequenceCompleted(CameraCaptureSession session,
+        public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session,
                 int sequenceId, long frameNumber) {
             // default empty implementation
         }
@@ -873,7 +882,7 @@
          * @see CaptureFailure#getSequenceId()
          * @see #onCaptureSequenceCompleted
          */
-        public void onCaptureSequenceAborted(CameraCaptureSession session,
+        public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
                 int sequenceId) {
             // default empty implementation
         }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d3b63f9..c2a6a44 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
@@ -91,6 +93,7 @@
          *
          * @return String representation of the key name
          */
+        @NonNull
         public String getName() {
             return mKey.getName();
         }
@@ -166,6 +169,7 @@
      * @param key The characteristics field to read.
      * @return The value of that key, or {@code null} if the field is not set.
      */
+    @Nullable
     public <T> T get(Key<T> key) {
         return mProperties.get(key);
     }
@@ -194,6 +198,7 @@
     /**
      * {@inheritDoc}
      */
+    @NonNull
     @Override
     public List<Key<?>> getKeys() {
         // List of keys is immutable; cache the results after we calculate them
@@ -227,6 +232,7 @@
      * @return List of keys supported by this CameraDevice for CaptureRequests.
      */
     @SuppressWarnings({"unchecked"})
+    @NonNull
     public List<CaptureRequest.Key<?>> getAvailableCaptureRequestKeys() {
         if (mAvailableRequestKeys == null) {
             Object crKey = CaptureRequest.Key.class;
@@ -258,6 +264,7 @@
      * @return List of keys supported by this CameraDevice for CaptureResults.
      */
     @SuppressWarnings({"unchecked"})
+    @NonNull
     public List<CaptureResult.Key<?>> getAvailableCaptureResultKeys() {
         if (mAvailableResultKeys == null) {
             Object crKey = CaptureResult.Key.class;
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index dad4fb6..d02f349 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -16,6 +16,9 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.IntDef;
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.params.OutputConfiguration;
@@ -23,6 +26,8 @@
 import android.view.Surface;
 
 import java.util.List;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * <p>The CameraDevice class is a representation of a single camera connected to an
@@ -124,6 +129,17 @@
      */
     public static final int TEMPLATE_MANUAL = 6;
 
+     /** @hide */
+     @Retention(RetentionPolicy.SOURCE)
+     @IntDef(
+         {TEMPLATE_PREVIEW,
+          TEMPLATE_STILL_CAPTURE,
+          TEMPLATE_RECORD,
+          TEMPLATE_VIDEO_SNAPSHOT,
+          TEMPLATE_ZERO_SHUTTER_LAG,
+          TEMPLATE_MANUAL })
+     public @interface RequestTemplate {};
+
     /**
      * Get the ID of this camera device.
      *
@@ -142,6 +158,7 @@
      * @see CameraManager#getCameraCharacteristics
      * @see CameraManager#getCameraIdList
      */
+    @NonNull
     public abstract String getId();
 
     /**
@@ -391,8 +408,8 @@
      * @see StreamConfigurationMap#getOutputSizes(int)
      * @see StreamConfigurationMap#getOutputSizes(Class)
      */
-    public abstract void createCaptureSession(List<Surface> outputs,
-            CameraCaptureSession.StateCallback callback, Handler handler)
+    public abstract void createCaptureSession(@NonNull List<Surface> outputs,
+            @NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
             throws CameraAccessException;
 
     /**
@@ -560,8 +577,9 @@
      * @see android.media.ImageWriter
      * @see android.media.ImageReader
      */
-    public abstract void createReprocessableCaptureSession(InputConfiguration inputConfig,
-            List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
+    public abstract void createReprocessableCaptureSession(@NonNull InputConfiguration inputConfig,
+            @NonNull List<Surface> outputs, @NonNull CameraCaptureSession.StateCallback callback,
+            @Nullable Handler handler)
             throws CameraAccessException;
 
     /**
@@ -591,7 +609,8 @@
      * @see #TEMPLATE_VIDEO_SNAPSHOT
      * @see #TEMPLATE_MANUAL
      */
-    public abstract CaptureRequest.Builder createCaptureRequest(int templateType)
+    @NonNull
+    public abstract CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType)
             throws CameraAccessException;
 
     /**
@@ -620,8 +639,9 @@
      * @see CameraDevice#createReprocessableCaptureSession
      * @see android.media.ImageWriter
      */
+    @NonNull
     public abstract CaptureRequest.Builder createReprocessCaptureRequest(
-            TotalCaptureResult inputResult) throws CameraAccessException;
+            @NonNull TotalCaptureResult inputResult) throws CameraAccessException;
 
     /**
      * Close the connection to this camera device as quickly as possible.
@@ -727,6 +747,16 @@
          */
         public static final int ERROR_CAMERA_SERVICE = 5;
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+            {ERROR_CAMERA_IN_USE,
+             ERROR_MAX_CAMERAS_IN_USE,
+             ERROR_CAMERA_DISABLED,
+             ERROR_CAMERA_DEVICE,
+             ERROR_CAMERA_SERVICE })
+        public @interface ErrorCode {};
+
         /**
          * The method called when a camera device has finished opening.
          *
@@ -736,7 +766,7 @@
          *
          * @param camera the camera device that has become opened
          */
-        public abstract void onOpened(CameraDevice camera); // Must implement
+        public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
 
         /**
          * The method called when a camera device has been closed with
@@ -749,7 +779,7 @@
          *
          * @param camera the camera device that has become closed
          */
-        public void onClosed(CameraDevice camera) {
+        public void onClosed(@NonNull CameraDevice camera) {
             // Default empty implementation
         }
 
@@ -781,7 +811,7 @@
          *
          * @param camera the device that has been disconnected
          */
-        public abstract void onDisconnected(CameraDevice camera); // Must implement
+        public abstract void onDisconnected(@NonNull CameraDevice camera); // Must implement
 
         /**
          * The method called when a camera device has encountered a serious error.
@@ -805,12 +835,14 @@
          * @param error The error code, one of the
          *     {@code StateCallback.ERROR_*} values.
          *
+         * @see #ERROR_CAMERA_IN_USE
+         * @see #ERROR_MAX_CAMERAS_IN_USE
+         * @see #ERROR_CAMERA_DISABLED
          * @see #ERROR_CAMERA_DEVICE
          * @see #ERROR_CAMERA_SERVICE
-         * @see #ERROR_CAMERA_DISABLED
-         * @see #ERROR_CAMERA_IN_USE
          */
-        public abstract void onError(CameraDevice camera, int error); // Must implement
+        public abstract void onError(@NonNull CameraDevice camera,
+                @ErrorCode int error); // Must implement
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d99cce7..20e1610 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -16,6 +16,9 @@
 
 package android.hardware.camera2;
 
+import android.annotation.RequiresPermission;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceListener;
@@ -86,6 +89,7 @@
      *
      * @return The list of currently connected camera devices.
      */
+    @NonNull
     public String[] getCameraIdList() throws CameraAccessException {
         synchronized (mLock) {
             // ID list creation handles various known failures in device enumeration, so only
@@ -121,7 +125,8 @@
      * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
      *             no looper.
      */
-    public void registerAvailabilityCallback(AvailabilityCallback callback, Handler handler) {
+    public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback,
+            @Nullable Handler handler) {
         if (handler == null) {
             Looper looper = Looper.myLooper();
             if (looper == null) {
@@ -142,7 +147,7 @@
      *
      * @param callback The callback to remove from the notification list
      */
-    public void unregisterAvailabilityCallback(AvailabilityCallback callback) {
+    public void unregisterAvailabilityCallback(@NonNull AvailabilityCallback callback) {
         CameraManagerGlobal.get().unregisterAvailabilityCallback(callback);
     }
 
@@ -168,7 +173,7 @@
      * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
      *             no looper.
      */
-    public void registerTorchCallback(TorchCallback callback, Handler handler) {
+    public void registerTorchCallback(@NonNull TorchCallback callback, @Nullable Handler handler) {
         if (handler == null) {
             Looper looper = Looper.myLooper();
             if (looper == null) {
@@ -188,7 +193,7 @@
      *
      * @param callback The callback to remove from the notification list
      */
-    public void unregisterTorchCallback(TorchCallback callback) {
+    public void unregisterTorchCallback(@NonNull TorchCallback callback) {
         CameraManagerGlobal.get().unregisterTorchCallback(callback);
     }
 
@@ -201,15 +206,13 @@
      *
      * @throws IllegalArgumentException if the cameraId does not match any
      *         known camera device.
-     * @throws CameraAccessException if the camera is disabled by device policy, or
-     *         the camera device has been disconnected.
-     * @throws SecurityException if the application does not have permission to
-     *         access the camera
+     * @throws CameraAccessException if the camera device has been disconnected.
      *
      * @see #getCameraIdList
      * @see android.app.admin.DevicePolicyManager#setCameraDisabled
      */
-    public CameraCharacteristics getCameraCharacteristics(String cameraId)
+    @NonNull
+    public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
             throws CameraAccessException {
         CameraCharacteristics characteristics = null;
 
@@ -431,8 +434,9 @@
      * @see #getCameraIdList
      * @see android.app.admin.DevicePolicyManager#setCameraDisabled
      */
-    public void openCamera(String cameraId, final CameraDevice.StateCallback callback,
-            Handler handler)
+    @RequiresPermission(android.Manifest.permission.CAMERA)
+    public void openCamera(@NonNull String cameraId,
+            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
             throws CameraAccessException {
 
         if (cameraId == null) {
@@ -444,7 +448,7 @@
                 handler = new Handler();
             } else {
                 throw new IllegalArgumentException(
-                        "Looper doesn't exist in the calling thread");
+                        "Handler argument is null, but no looper exists in the calling thread");
             }
         }
 
@@ -490,7 +494,8 @@
      *             or previously available camera device, or the camera device doesn't have a
      *             flash unit.
      */
-    public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
+    public void setTorchMode(@NonNull String cameraId, boolean enabled)
+            throws CameraAccessException {
         CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
     }
 
@@ -517,7 +522,7 @@
          *
          * @param cameraId The unique identifier of the new camera.
          */
-        public void onCameraAvailable(String cameraId) {
+        public void onCameraAvailable(@NonNull String cameraId) {
             // default empty implementation
         }
 
@@ -532,7 +537,7 @@
          *
          * @param cameraId The unique identifier of the disconnected camera.
          */
-        public void onCameraUnavailable(String cameraId) {
+        public void onCameraUnavailable(@NonNull String cameraId) {
             // default empty implementation
         }
     }
@@ -572,7 +577,7 @@
          * @param cameraId The unique identifier of the camera whose torch mode has become
          *                 unavailable.
          */
-        public void onTorchModeUnavailable(String cameraId) {
+        public void onTorchModeUnavailable(@NonNull String cameraId) {
             // default empty implementation
         }
 
@@ -589,7 +594,7 @@
          *                off. {@code false} when the torch mode has becomes off and available to
          *                be turned on.
          */
-        public void onTorchModeChanged(String cameraId, boolean enabled) {
+        public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
             // default empty implementation
         }
     }
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 6baa660..cf091a9 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
@@ -103,6 +104,7 @@
      * @return List of the keys contained in this map.
      */
     @SuppressWarnings("unchecked")
+    @NonNull
     public List<TKey> getKeys() {
         Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass();
         return Collections.unmodifiableList(
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index c168ff1..8bb33f1 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -15,6 +15,12 @@
  */
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A report of failed capture for a single image capture from the image sensor.
  *
@@ -43,6 +49,13 @@
      */
     public static final int REASON_FLUSHED = 1;
 
+     /** @hide */
+     @Retention(RetentionPolicy.SOURCE)
+     @IntDef(
+         {REASON_ERROR,
+          REASON_FLUSHED })
+     public @interface FailureReason {};
+
     private final CaptureRequest mRequest;
     private final int mReason;
     private final boolean mDropped;
@@ -52,8 +65,8 @@
     /**
      * @hide
      */
-    public CaptureFailure(CaptureRequest request, int reason, boolean dropped, int sequenceId,
-            long frameNumber) {
+    public CaptureFailure(CaptureRequest request, int reason,
+            boolean dropped, int sequenceId, long frameNumber) {
         mRequest = request;
         mReason = reason;
         mDropped = dropped;
@@ -81,6 +94,7 @@
      *
      * @return The request associated with this failed capture. Never {@code null}.
      */
+    @NonNull
     public CaptureRequest getRequest() {
         return mRequest;
     }
@@ -110,6 +124,7 @@
      * @see #REASON_ERROR
      * @see #REASON_FLUSHED
      */
+    @FailureReason
     public int getReason() {
         return mReason;
     }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5fb9abc..8f7b983 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
@@ -117,6 +119,7 @@
          *
          * @return String representation of the key name
          */
+        @NonNull
         public String getName() {
             return mKey.getName();
         }
@@ -239,6 +242,7 @@
      * @param key The result field to read.
      * @return The value of that key, or {@code null} if the field is not set.
      */
+    @Nullable
     public <T> T get(Key<T> key) {
         return mSettings.get(key);
     }
@@ -268,6 +272,7 @@
      * {@inheritDoc}
      */
     @Override
+    @NonNull
     public List<Key<?>> getKeys() {
         // Force the javadoc for this function to show up on the CaptureRequest page
         return super.getKeys();
@@ -286,6 +291,7 @@
      *     no tag has been set.
      * @see Builder#setTag
      */
+    @Nullable
     public Object getTag() {
         return mUserTag;
     }
@@ -476,7 +482,7 @@
          *
          * @param outputTarget Surface to use as an output target for this request
          */
-        public void addTarget(Surface outputTarget) {
+        public void addTarget(@NonNull Surface outputTarget) {
             mRequest.mSurfaceSet.add(outputTarget);
         }
 
@@ -487,7 +493,7 @@
          *
          * @param outputTarget Surface to use as an output target for this request
          */
-        public void removeTarget(Surface outputTarget) {
+        public void removeTarget(@NonNull Surface outputTarget) {
             mRequest.mSurfaceSet.remove(outputTarget);
         }
 
@@ -499,7 +505,7 @@
          * @param value The value to set the field to, which must be of a matching
          * type to the key.
          */
-        public <T> void set(Key<T> key, T value) {
+        public <T> void set(@NonNull Key<T> key, T value) {
             mRequest.mSettings.set(key, value);
         }
 
@@ -512,6 +518,7 @@
          * @param key The metadata field to read.
          * @return The value of that key, or {@code null} if the field is not set.
          */
+        @Nullable
         public <T> T get(Key<T> key) {
             return mRequest.mSettings.get(key);
         }
@@ -527,7 +534,7 @@
          * @param tag an arbitrary Object to store with this request
          * @see CaptureRequest#getTag
          */
-        public void setTag(Object tag) {
+        public void setTag(@Nullable Object tag) {
             mRequest.mUserTag = tag;
         }
 
@@ -543,6 +550,7 @@
          * @return A new capture request instance, ready for submission to the
          * camera device.
          */
+        @NonNull
         public CaptureRequest build() {
             return new CaptureRequest(mRequest);
         }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0277c5b..f4017d0 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PublicKey;
@@ -102,6 +104,7 @@
          *
          * @return String representation of the key name
          */
+        @NonNull
         public String getName() {
             return mKey.getName();
         }
@@ -216,6 +219,7 @@
      * @param key The result field to read.
      * @return The value of that key, or {@code null} if the field is not set.
      */
+    @Nullable
     public <T> T get(Key<T> key) {
         T value = mResults.get(key);
         if (VERBOSE) Log.v(TAG, "#get for Key = " + key.getName() + ", returned value = " + value);
@@ -259,6 +263,7 @@
      * {@inheritDoc}
      */
     @Override
+    @NonNull
     public List<Key<?>> getKeys() {
         // Force the javadoc for this function to show up on the CaptureResult page
         return super.getKeys();
@@ -285,6 +290,7 @@
      *
      * @return The request associated with this result. Never {@code null}.
      */
+    @NonNull
     public CaptureRequest getRequest() {
         return mRequest;
     }
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index f16d650..70afe5b 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -16,6 +16,9 @@
 
 package android.hardware.camera2;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.ImageFormat;
@@ -80,7 +83,8 @@
      *          {@link android.hardware.camera2.CameraCharacteristics}.
      * @param metadata a metadata object to generate tags from.
      */
-    public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {
+    public DngCreator(@NonNull CameraCharacteristics characteristics,
+            @NonNull CaptureResult metadata) {
         if (characteristics == null || metadata == null) {
             throw new IllegalArgumentException("Null argument to DngCreator constructor");
         }
@@ -126,6 +130,7 @@
      *                    </ul>
      * @return this {@link #DngCreator} object.
      */
+    @NonNull
     public DngCreator setOrientation(int orientation) {
         if (orientation < ExifInterface.ORIENTATION_UNDEFINED ||
                 orientation > ExifInterface.ORIENTATION_ROTATE_270) {
@@ -150,7 +155,8 @@
      * @throws java.lang.IllegalArgumentException if the given thumbnail image has a dimension
      *      larger than {@link #MAX_THUMBNAIL_DIMENSION}.
      */
-    public DngCreator setThumbnail(Bitmap pixels) {
+    @NonNull
+    public DngCreator setThumbnail(@NonNull Bitmap pixels) {
         if (pixels == null) {
             throw new IllegalArgumentException("Null argument to setThumbnail");
         }
@@ -185,7 +191,8 @@
      * @throws java.lang.IllegalArgumentException if the given thumbnail image has a dimension
      *      larger than {@link #MAX_THUMBNAIL_DIMENSION}.
      */
-    public DngCreator setThumbnail(Image pixels) {
+    @NonNull
+    public DngCreator setThumbnail(@NonNull Image pixels) {
         if (pixels == null) {
             throw new IllegalArgumentException("Null argument to setThumbnail");
         }
@@ -226,7 +233,8 @@
      * @throws java.lang.IllegalArgumentException if the given location object doesn't
      *          contain enough information to set location metadata.
      */
-    public DngCreator setLocation(Location location) {
+    @NonNull
+    public DngCreator setLocation(@NonNull Location location) {
         if (location == null) {
             throw new IllegalArgumentException("Null location passed to setLocation");
         }
@@ -258,7 +266,8 @@
      * @param description the user description string.
      * @return this {@link #DngCreator} object.
      */
-    public DngCreator setDescription(String description) {
+    @NonNull
+    public DngCreator setDescription(@NonNull String description) {
         if (description == null) {
             throw new IllegalArgumentException("Null description passed to setDescription.");
         }
@@ -293,8 +302,8 @@
      *          set to write a well-formatted DNG file.
      * @throws java.lang.IllegalArgumentException if the size passed in does not match the
      */
-    public void writeInputStream(OutputStream dngOutput, Size size, InputStream pixels, long offset)
-            throws IOException {
+    public void writeInputStream(@NonNull OutputStream dngOutput, @NonNull Size size,
+            @NonNull InputStream pixels, @IntRange(from=0) long offset) throws IOException {
         if (dngOutput == null) {
             throw new IllegalArgumentException("Null dngOutput passed to writeInputStream");
         } else if (size == null) {
@@ -345,7 +354,8 @@
      * @throws java.lang.IllegalStateException if not enough metadata information has been
      *          set to write a well-formatted DNG file.
      */
-    public void writeByteBuffer(OutputStream dngOutput, Size size, ByteBuffer pixels, long offset)
+    public void writeByteBuffer(@NonNull OutputStream dngOutput, @NonNull Size size,
+            @NonNull ByteBuffer pixels, @IntRange(from=0) long offset)
             throws IOException {
         if (dngOutput == null) {
             throw new IllegalArgumentException("Null dngOutput passed to writeByteBuffer");
@@ -381,7 +391,8 @@
      * @throws java.lang.IllegalStateException if not enough metadata information has been
      *          set to write a well-formatted DNG file.
      */
-    public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {
+    public void writeImage(@NonNull OutputStream dngOutput, @NonNull Image pixels)
+            throws IOException {
         if (dngOutput == null) {
             throw new IllegalArgumentException("Null dngOutput to writeImage");
         } else if (pixels == null) {
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index fb3c098..657745c 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.NonNull;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 
@@ -96,6 +97,7 @@
      *
      * @return unmodifiable list of partial results
      */
+    @NonNull
     public List<CaptureResult> getPartialResults() {
         return Collections.unmodifiableList(mPartialResults);
     }
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 9046e81..7f4a76c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -67,8 +67,6 @@
     private final TaskSingleDrainer mIdleDrainer;
     /** Drain state transitions from BUSY -> IDLE */
     private final TaskSingleDrainer mAbortDrainer;
-    /** Drain the UNCONFIGURED state transition */
-    private final TaskSingleDrainer mUnconfigureDrainer;
 
     /** This session is closed; all further calls will throw ISE */
     private boolean mClosed = false;
@@ -121,8 +119,6 @@
                 /*name*/"idle");
         mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
                 /*name*/"abort");
-        mUnconfigureDrainer = new TaskSingleDrainer(mDeviceHandler, new UnconfigureDrainListener(),
-                /*name*/"unconf");
 
         // CameraDevice should call configureOutputs and have it finish before constructing us
 
@@ -572,26 +568,6 @@
             @Override
             public void onUnconfigured(CameraDevice camera) {
                 if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigured");
-                synchronized (session) {
-                    // Ignore #onUnconfigured before #close is called.
-                    //
-                    // Normally, this is reached when this session is closed and no immediate other
-                    // activity happens for the camera, in which case the camera is configured to
-                    // null streams by this session and the UnconfigureDrainer task is started.
-                    // However, we can also end up here if
-                    //
-                    // 1) Session is closed
-                    // 2) New session is created before this session finishes closing, setting
-                    //    mSkipUnconfigure and therefore this session does not configure null or
-                    //    start the UnconfigureDrainer task.
-                    // 3) And then the new session fails to be created, so onUnconfigured fires
-                    //    _anyway_.
-                    // In this second case, need to not finish a task that was never started, so
-                    // guard with mSkipUnconfigure
-                    if (mClosed && mConfigureSuccess && !mSkipUnconfigure) {
-                        mUnconfigureDrainer.taskFinished();
-                    }
-                }
             }
 
             @Override
@@ -656,6 +632,19 @@
              * then the drain immediately finishes.
              */
             if (VERBOSE) Log.v(TAG, mIdString + "onSequenceDrained");
+
+
+            // Fire session close as soon as all sequences are complete.
+            // We may still need to unconfigure the device, but a new session might be created
+            // past this point, and notifications would then stop to this instance.
+            mStateCallback.onClosed(CameraCaptureSessionImpl.this);
+
+            // Fast path: A new capture session has replaced this one; don't wait for abort/idle
+            // as we won't get state updates any more anyway.
+            if (mSkipUnconfigure) {
+                return;
+            }
+
             mAbortDrainer.beginDrain();
         }
     }
@@ -673,6 +662,12 @@
                  *
                  * If the camera is already "IDLE", then the drain immediately finishes.
                  */
+
+                // Fast path: A new capture session has replaced this one; don't wait for idle
+                // as we won't get state updates any more anyway.
+                if (mSkipUnconfigure) {
+                    return;
+                }
                 mIdleDrainer.beginDrain();
             }
         }
@@ -691,7 +686,7 @@
                  * The device is now IDLE, and has settled. It will not transition to
                  * ACTIVE or BUSY again by itself.
                  *
-                 * It's now safe to unconfigure the outputs and after it's done invoke #onClosed.
+                 * It's now safe to unconfigure the outputs.
                  *
                  * This operation is idempotent; a session will not be closed twice.
                  */
@@ -699,45 +694,31 @@
                         Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
                                 mSkipUnconfigure);
 
-                    // Fast path: A new capture session has replaced this one; don't unconfigure.
+                    // Fast path: A new capture session has replaced this one; don't wait for idle
+                    // as we won't get state updates any more anyway.
                     if (mSkipUnconfigure) {
-                        mStateCallback.onClosed(CameraCaptureSessionImpl.this);
                         return;
                     }
 
-                    // Slow path: #close was called explicitly on this session; unconfigure first
-                    mUnconfigureDrainer.taskStarted();
-
+                    // Final slow path: unconfigure the camera, no session has replaced us and
+                    // everything is idle.
                     try {
                         // begin transition to unconfigured
                         mDeviceImpl.configureStreamsChecked(null, null);
                     } catch (CameraAccessException e) {
                         // OK: do not throw checked exceptions.
-                        Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
+                        Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e);
 
                         // TODO: call onError instead of onClosed if this happens
                     } catch (IllegalStateException e) {
-                        // Camera is already closed, so go straight to the close callback
+                        // Camera is already closed, so nothing left to do
                         if (VERBOSE) Log.v(TAG, mIdString +
                                 "Camera was already closed or busy, skipping unconfigure");
-                        mUnconfigureDrainer.taskFinished();
                     }
 
-                    mUnconfigureDrainer.beginDrain();
                 }
             }
         }
     }
 
-    private class UnconfigureDrainListener implements TaskDrainer.DrainListener {
-        @Override
-
-        public void onDrained() {
-            if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigureDrained");
-            synchronized (CameraCaptureSessionImpl.this) {
-                // The device has finished unconfiguring. It's now fully closed.
-                mStateCallback.onClosed(CameraCaptureSessionImpl.this);
-            }
-        }
-    }
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 4508dc8..c4e8b15 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -607,6 +607,8 @@
     }
 
     public void prepare(Surface surface) throws CameraAccessException {
+        if (surface == null) throw new IllegalArgumentException("Surface is null");
+
         synchronized(mInterfaceLock) {
             int streamId = -1;
             for (int i = 0; i < mConfiguredOutputs.size(); i++) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 26878c0..e175e9a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1906,9 +1906,6 @@
      *
      * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
      *        if no global HTTP proxy is set.
-     *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public ProxyInfo getGlobalProxy() {
@@ -1920,6 +1917,28 @@
     }
 
     /**
+     * Retrieve the global HTTP proxy, or if no global HTTP proxy is set, a
+     * network-specific HTTP proxy.  If {@code network} is null, the
+     * network-specific proxy returned is the proxy of the default active
+     * network.
+     *
+     * @return {@link ProxyInfo} for the current global HTTP proxy, or if no
+     *         global HTTP proxy is set, {@code ProxyInfo} for {@code network},
+     *         or when {@code network} is {@code null},
+     *         the {@code ProxyInfo} for the default active network.  Returns
+     *         {@code null} when no proxy applies or the caller doesn't have
+     *         permission to use {@code network}.
+     * @hide
+     */
+    public ProxyInfo getProxyForNetwork(Network network) {
+        try {
+            return mService.getProxyForNetwork(network);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Get the current default HTTP proxy settings.  If a global proxy is set it will be returned,
      * otherwise if this process is bound to a {@link Network} using
      * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise
@@ -1929,19 +1948,7 @@
      *        HTTP proxy is active.
      */
     public ProxyInfo getDefaultProxy() {
-        final Network network = getBoundNetworkForProcess();
-        if (network != null) {
-            final ProxyInfo globalProxy = getGlobalProxy();
-            if (globalProxy != null) return globalProxy;
-            final LinkProperties lp = getLinkProperties(network);
-            if (lp != null) return lp.getHttpProxy();
-            return null;
-        }
-        try {
-            return mService.getDefaultProxy();
-        } catch (RemoteException e) {
-            return null;
-        }
+        return getProxyForNetwork(getBoundNetworkForProcess());
     }
 
     /**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 77200a5..89d23a2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -104,15 +104,15 @@
 
     void setGlobalProxy(in ProxyInfo p);
 
-    ProxyInfo getDefaultProxy();
+    ProxyInfo getProxyForNetwork(in Network nework);
 
-    boolean prepareVpn(String oldPackage, String newPackage);
+    boolean prepareVpn(String oldPackage, String newPackage, int userId);
 
-    void setVpnPackageAuthorization(boolean authorized);
+    void setVpnPackageAuthorization(String packageName, int userId, boolean authorized);
 
     ParcelFileDescriptor establishVpn(in VpnConfig config);
 
-    VpnConfig getVpnConfig();
+    VpnConfig getVpnConfig(int userId);
 
     void startLegacyVpn(in VpnProfile profile);
 
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
index 7e1c05b..add8774 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -75,7 +75,6 @@
     private boolean mRunning;
     final private Thread mObserverThread;
 
-    // TODO: consider passing in a NetworkInterface object from the caller.
     public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
         mInterfaceName = ifName;
         int ifIndex = -1;
@@ -154,6 +153,12 @@
         }
     }
 
+    private boolean stillRunning() {
+        synchronized (mLock) {
+            return mRunning;
+        }
+    }
+
     public void updateLinkProperties(LinkProperties lp) {
         if (!mInterfaceName.equals(lp.getInterfaceName())) {
             // TODO: figure out how to cope with interface changes.
@@ -204,6 +209,47 @@
         }
     }
 
+    public void probeAll() {
+        Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+        synchronized (mLock) {
+            ipProbeList.addAll(mIpWatchList);
+        }
+        for (InetAddress target : ipProbeList) {
+            if (!stillRunning()) { break; }
+            probeIp(target);
+        }
+    }
+
+    private void probeIp(InetAddress ip) {
+        // This currently does not cause neighbor probing if the target |ip|
+        // has been confirmed reachable within the past "delay_probe_time"
+        // seconds, i.e. within the past 5 seconds.
+        //
+        // TODO: replace with a transition directly to NUD_PROBE state once
+        // kernels are updated to do so correctly.
+        if (DBG) { Log.d(TAG, "Probing ip=" + ip.getHostAddress()); }
+
+        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+                1, ip, StructNdMsg.NUD_DELAY, mInterfaceIndex, null);
+        NetlinkSocket nlSocket = null;
+
+        try {
+            nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+            nlSocket.connectToKernel();
+            nlSocket.sendMessage(msg, 0, msg.length, 300);
+            final NetlinkMessage response = NetlinkMessage.parse(nlSocket.recvMessage(300));
+            if (response != null && response instanceof NetlinkErrorMessage) {
+                Log.e(TAG, "Error probing ip=" + response.toString());
+            }
+        } catch (ErrnoException | InterruptedIOException | SocketException e) {
+            Log.d(TAG, "Error probing ip=" + ip.getHostAddress(), e);
+        }
+
+        if (nlSocket != null) {
+            nlSocket.close();
+        }
+    }
+
 
     private final class NetlinkSocketObserver implements Runnable {
         private static final String TAG = "NetlinkSocketObserver";
@@ -242,12 +288,6 @@
             if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
         }
 
-        private boolean stillRunning() {
-            synchronized (mLock) {
-                return mRunning;
-            }
-        }
-
         private void clearNetlinkSocket() {
             if (mSocket != null) {
                 mSocket.close();
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 67ecb5d..754c6b3 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -247,12 +247,7 @@
             throw new IOException("No ConnectivityManager yet constructed, please construct one");
         }
         // TODO: Should this be optimized to avoid fetching the global proxy for every request?
-        ProxyInfo proxyInfo = cm.getGlobalProxy();
-        if (proxyInfo == null) {
-            // TODO: Should this be optimized to avoid fetching LinkProperties for every request?
-            final LinkProperties lp = cm.getLinkProperties(this);
-            if (lp != null) proxyInfo = lp.getHttpProxy();
-        }
+        final ProxyInfo proxyInfo = cm.getProxyForNetwork(this);
         java.net.Proxy proxy = null;
         if (proxyInfo != null) {
             proxy = proxyInfo.makeProxy();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ab70485..cf747cf 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -619,6 +619,7 @@
                 case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
                 case NET_CAPABILITY_TRUSTED:        capabilities += "TRUSTED"; break;
                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
+                case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
             }
             if (++i < types.length) capabilities += "&";
         }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 29dd8ad..4487cab 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -194,6 +194,12 @@
     public native static boolean protectFromVpn(int socketfd);
 
     /**
+     * Determine if {@code uid} can access network designated by {@code netId}.
+     * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
+     */
+    public native static boolean queryUserAccess(int uid, int netId);
+
+    /**
      * Convert a IPv4 address from an integer to an InetAddress.
      * @param hostAddress an int corresponding to the IPv4 address in network byte order
      */
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index a0e65eb..2bb48b3 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -156,7 +156,7 @@
      */
     public static Intent prepare(Context context) {
         try {
-            if (getService().prepareVpn(context.getPackageName(), null)) {
+            if (getService().prepareVpn(context.getPackageName(), null, UserHandle.myUserId())) {
                 return null;
             }
         } catch (RemoteException e) {
@@ -182,10 +182,11 @@
         String packageName = context.getPackageName();
         try {
             // Only prepare if we're not already prepared.
-            if (!cm.prepareVpn(packageName, null)) {
-                cm.prepareVpn(null, packageName);
+            int userId = UserHandle.myUserId();
+            if (!cm.prepareVpn(packageName, null, userId)) {
+                cm.prepareVpn(null, packageName, userId);
             }
-            cm.setVpnPackageAuthorization(true);
+            cm.setVpnPackageAuthorization(packageName, userId, true);
         } catch (RemoteException e) {
             // ignore
         }
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
index d4b572c..b5f5817 100644
--- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
@@ -21,9 +21,11 @@
 import android.net.netlink.StructNlAttr;
 import android.net.netlink.StructNlMsgHdr;
 import android.net.netlink.NetlinkMessage;
+import android.system.OsConstants;
 import android.util.Log;
 
 import java.net.InetAddress;
+import java.net.Inet6Address;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
@@ -131,6 +133,34 @@
         return bytes;
     }
 
+    /**
+     * A convenience method to create an RTM_NEWNEIGH message, to modify
+     * the kernel's state information for a specific neighbor.
+     */
+    public static byte[] newNewNeighborMessage(
+            int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
+        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
+        nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_REPLACE;
+        nlmsghdr.nlmsg_seq = seqNo;
+
+        final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
+        msg.mNdmsg = new StructNdMsg();
+        msg.mNdmsg.ndm_family =
+                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+        msg.mNdmsg.ndm_ifindex = ifIndex;
+        msg.mNdmsg.ndm_state = nudState;
+        msg.mDestination = ip;
+        msg.mLinkLayerAddr = llAddr;  // might be null
+
+        final byte[] bytes = new byte[msg.getRequiredSpace()];
+        nlmsghdr.nlmsg_len = bytes.length;
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        msg.pack(byteBuffer);
+        return bytes;
+    }
+
     private StructNdMsg mNdmsg;
     private InetAddress mDestination;
     private byte[] mLinkLayerAddr;
@@ -166,6 +196,41 @@
         return mCacheInfo;
     }
 
+    public int getRequiredSpace() {
+        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
+        if (mDestination != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
+        }
+        if (mLinkLayerAddr != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
+        }
+        // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
+        // attributes appended.  Fix later, if necessary.
+        return spaceRequired;
+    }
+
+    private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
+        final StructNlAttr nlAttr = new StructNlAttr();
+        nlAttr.nla_type = nlType;
+        nlAttr.nla_value = nlValue;
+        nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
+        nlAttr.pack(byteBuffer);
+    }
+
+    public void pack(ByteBuffer byteBuffer) {
+        getHeader().pack(byteBuffer) ;
+        mNdmsg.pack(byteBuffer);
+
+        if (mDestination != null) {
+            packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
+        }
+        if (mLinkLayerAddr != null) {
+            packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
+        }
+    }
+
     @Override
     public String toString() {
         final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/core/java/android/net/netlink/StructNdMsg.java
index e66d45d..ca1cbbb 100644
--- a/core/java/android/net/netlink/StructNdMsg.java
+++ b/core/java/android/net/netlink/StructNdMsg.java
@@ -123,9 +123,7 @@
         ndm_family = (byte) OsConstants.AF_UNSPEC;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the exception
         // of usage within unittests.
@@ -136,7 +134,6 @@
         byteBuffer.putShort(ndm_state);
         byteBuffer.put(ndm_flags);
         byteBuffer.put(ndm_type);
-        return true;
     }
 
     public boolean nudConnected() {
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/core/java/android/net/netlink/StructNlAttr.java
index 9aef4c7..597a6aa 100644
--- a/core/java/android/net/netlink/StructNlAttr.java
+++ b/core/java/android/net/netlink/StructNlAttr.java
@@ -116,6 +116,14 @@
         }
     }
 
+    public void pack(ByteBuffer byteBuffer) {
+        final int originalPosition = byteBuffer.position();
+        byteBuffer.putShort(nla_len);
+        byteBuffer.putShort(nla_type);
+        byteBuffer.put(nla_value);
+        byteBuffer.position(originalPosition + getAlignedLength());
+    }
+
     @Override
     public String toString() {
         return "StructNlAttr{ "
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/core/java/android/net/netlink/StructNlMsgErr.java
index 5da19a2..6b02650 100644
--- a/core/java/android/net/netlink/StructNlMsgErr.java
+++ b/core/java/android/net/netlink/StructNlMsgErr.java
@@ -57,9 +57,7 @@
         msg = null;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the possible
         // exception of usage within unittests.
@@ -67,7 +65,6 @@
         if (msg != null) {
             msg.pack(byteBuffer);
         }
-        return true;
     }
 
     @Override
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/core/java/android/net/netlink/StructNlMsgHdr.java
index 67925ac..98ab5e7 100644
--- a/core/java/android/net/netlink/StructNlMsgHdr.java
+++ b/core/java/android/net/netlink/StructNlMsgHdr.java
@@ -39,6 +39,12 @@
     public static final short NLM_F_ROOT    = 0x0100;
     public static final short NLM_F_MATCH   = 0x0200;
     public static final short NLM_F_DUMP    = NLM_F_ROOT|NLM_F_MATCH;
+    // Flags for a NEW request.
+    public static final short NLM_F_REPLACE   = 0x100;
+    public static final short NLM_F_EXCL      = 0x200;
+    public static final short NLM_F_CREATE    = 0x400;
+    public static final short NLM_F_APPEND    = 0x800;
+
 
     public static String stringForNlMsgFlags(short flags) {
         final StringBuilder sb = new StringBuilder();
@@ -106,9 +112,7 @@
         nlmsg_pid = 0;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the possible
         // exception of usage within unittests.
@@ -117,7 +121,6 @@
         byteBuffer.putShort(nlmsg_flags);
         byteBuffer.putInt(nlmsg_seq);
         byteBuffer.putInt(nlmsg_pid);
-        return true;
     }
 
     @Override
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index f212daf..aa4b051 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -36,6 +36,7 @@
     ParcelFileDescriptor getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
+    boolean canAddMoreManagedProfiles();
     UserInfo getProfileParent(int userHandle);
     UserInfo getUserInfo(int userHandle);
     long getUserCreationTime(int userHandle);
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9a0d0d0..e523285 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -136,4 +136,8 @@
     public abstract void setDeviceIdleMode(boolean enabled);
 
     public abstract void setDeviceIdleWhitelist(int[] appids);
+
+    public abstract void updateUidProcState(int uid, int procState);
+
+    public abstract void uidGone(int uid);
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3dee68c..11043b3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -933,6 +933,22 @@
     }
 
     /**
+     * Checks whether it's possible to add more managed profiles. Caller must hold the MANAGE_USERS
+     * permission.
+     *
+     * @return true if more managed profiles can be added, false if limit has been reached.
+     * @hide
+     */
+    public boolean canAddMoreManagedProfiles() {
+        try {
+            return mService.canAddMoreManagedProfiles();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not check if we can add more managed profiles", re);
+            return false;
+        }
+    }
+
+    /**
      * Returns list of the profiles of userHandle including
      * userHandle itself.
      * Note that this returns both enabled and not enabled profiles. See
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 9623695..04e54aa 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
     public final int flags;
     public long size;
     public String label;
+    /** Hacky; don't rely on this count */
+    public int volumeCount;
 
     public DiskInfo(String id, int flags) {
         this.id = Preconditions.checkNotNull(id);
@@ -61,6 +63,7 @@
         flags = parcel.readInt();
         size = parcel.readLong();
         label = parcel.readString();
+        volumeCount = parcel.readInt();
     }
 
     public @NonNull String getId() {
@@ -181,5 +184,6 @@
         parcel.writeInt(this.flags);
         parcel.writeLong(size);
         parcel.writeString(label);
+        parcel.writeInt(volumeCount);
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ef0dc3e..37645b5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5417,6 +5417,14 @@
         public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application";
 
         /**
+         * Specifies whether the current app context on scren (assist data) will be sent to the
+         * assist application (active voice interaction service).
+         *
+         * @hide
+         */
+        public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled";
+
+        /**
          * Names of the packages that the current user has explicitly allowed to
          * see all of the user's notifications, separated by ':'.
          *
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 8c89ddb..77e2125 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -77,6 +77,7 @@
     public static final int START_WITH_ASSIST = 1<<0;
 
     /**
+     * @hide
      * Flag for use with {@link #showSession}: request that the session be started with
      * a screen shot of the currently focused activity.
      */
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 71b7f76..f122d10 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -820,6 +820,7 @@
     public void onHandleAssist(Bundle assistBundle) {
     }
 
+    /** @hide */
     public void onHandleScreenshot(Bitmap screenshot) {
     }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 016541f..b93a4a5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -168,8 +168,6 @@
         final Rect mFinalStableInsets = new Rect();
         final Configuration mConfiguration = new Configuration();
 
-        private boolean mWindowIsRound;
-
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
         IWindowSession mSession;
@@ -640,7 +638,6 @@
                         // Retrieve watch round info
                         TypedArray windowStyle = obtainStyledAttributes(
                                 com.android.internal.R.styleable.Window);
-                        mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources());
                         windowStyle.recycle();
 
                         // Add window
@@ -776,7 +773,8 @@
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom;
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
-                                    null, mFinalStableInsets, mWindowIsRound);
+                                    null, mFinalStableInsets,
+                                    getResources().getConfiguration().isScreenRound());
                             onApplyWindowInsets(insets);
                         }
 
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 92e874f..dc965ed 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -134,6 +134,24 @@
     }
 
     /**
+     * @hide
+     * Removes the mapping from the specified key, if there was any, returning the old value.
+     */
+    public E removeReturnOld(int key) {
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                final E old = (E) mValues[i];
+                mValues[i] = DELETED;
+                mGarbage = true;
+                return old;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Alias for {@link #delete(int)}.
      */
     public void remove(int key) {
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 9f202a9..9f00455 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -44,6 +44,12 @@
      */
     public static final int TYPE_FLOATING = 1;
 
+    /**
+     * Default snooze time.
+     */
+    public static final int SNOOZE_TIME_DEFAULT =
+            ViewConfiguration.getDefaultActionModeSnoozeTime();
+
     private Object mTag;
     private boolean mTitleOptionalHint;
     private int mType = TYPE_PRIMARY;
@@ -207,6 +213,19 @@
     public void invalidateContentRect() {}
 
     /**
+     * Hide the action mode view from obstructing the content below for a short period.
+     * This only makes sense for action modes that support dynamic positioning on the screen.
+     * If this method is called again before the snooze time expires, the later snooze will
+     * cancel the former and then take effect.
+     * NOTE that there is an internal limit to how long the mode can be snoozed for. It's typically
+     * about a few seconds.
+     *
+     * @param snoozeTime The number of milliseconds to snooze for.
+     * @see #SNOOZE_TIME_DEFAULT
+     */
+    public void snooze(int snoozeTime) {}
+
+    /**
      * Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
      * have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
      */
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4e91ad4..8c6fa3f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -213,6 +213,11 @@
     private static final int OVERFLING_DISTANCE = 6;
 
     /**
+     * Default time to snooze an action mode for.
+     */
+    private static final int ACTION_MODE_SNOOZE_TIME_DEFAULT = 2000;
+
+    /**
      * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior.
      * These constants must match the definition in res/values/config.xml.
      */
@@ -732,6 +737,13 @@
     }
 
     /**
+     * @return the default duration in milliseconds for {@link ActionMode#snooze(int)}.
+     */
+    public static int getDefaultActionModeSnoozeTime() {
+        return ACTION_MODE_SNOOZE_TIME_DEFAULT;
+    }
+
+    /**
      * Report if the device has a permanent menu key available to the user.
      *
      * <p>As of Android 3.0, devices may not have a permanent menu key available.
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index bd45007..f18b7ac 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -80,12 +80,18 @@
 
     /**
      * The interpolator of the underlying Animator object. By default, we don't set the interpolator
-     * on the Animator and just use its default interpolator. If the interpolator is set to a
-     * non-null value on this Animator, then we use the interpolator that it was set to.
+     * on the Animator and just use its default interpolator. If the interpolator is ever set on
+     * this Animator, then we use the interpolator that it was set to.
      */
     private TimeInterpolator mInterpolator;
 
     /**
+     * A flag indicating whether the interpolator has been set on this object. If not, we don't set
+     * the interpolator on the underlying Animator, but instead just use its default interpolator.
+     */
+    private boolean mInterpolatorSet = false;
+
+    /**
      * Listener for the lifecycle events of the underlying ValueAnimator object.
      */
     private Animator.AnimatorListener mListener = null;
@@ -332,6 +338,7 @@
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+        mInterpolatorSet = true;
         mInterpolator = interpolator;
         return this;
     }
@@ -342,7 +349,7 @@
      * @return The timing interpolator for this animation.
      */
     public TimeInterpolator getInterpolator() {
-        if (mInterpolator != null) {
+        if (mInterpolatorSet) {
             return mInterpolator;
         } else {
             // Just return the default from ValueAnimator, since that's what we'd get if
@@ -890,7 +897,7 @@
         if (mDurationSet) {
             animator.setDuration(mDuration);
         }
-        if (mInterpolator != null) {
+        if (mInterpolatorSet) {
             animator.setInterpolator(mInterpolator);
         }
         animator.start();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b7d902c..c4f9209 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -122,7 +122,6 @@
     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
 
     // properties used by emulator to determine display shape
-    public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
     public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
             "ro.emu.win_outset_bottom_px";
 
@@ -341,8 +340,6 @@
     /** Set to true once doDie() has been called. */
     private boolean mRemoved;
 
-    private final boolean mWindowIsRound;
-
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -397,7 +394,6 @@
         mChoreographer = Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
-        mWindowIsRound = ScreenShapeHelper.getWindowIsRound(context.getResources());
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -1271,7 +1267,8 @@
                 stableInsets = mPendingStableInsets;
             }
             mLastWindowInsets = new WindowInsets(contentInsets,
-                    null /* windowDecorInsets */, stableInsets, mWindowIsRound);
+                    null /* windowDecorInsets */, stableInsets,
+                    mContext.getResources().getConfiguration().isScreenRound());
         }
         return mLastWindowInsets;
     }
@@ -2024,8 +2021,8 @@
                 mLastWasImTarget = imTarget;
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null && imTarget) {
-                    imm.startGettingWindowFocus(mView);
-                    imm.onWindowFocus(mView, mView.findFocus(),
+                    imm.onPreWindowFocus(mView, true /* hasWindowFocus */);
+                    imm.onPostWindowFocus(mView, mView.findFocus(),
                             mWindowAttributes.softInputMode,
                             !mHasHadWindowFocus, mWindowAttributes.flags);
                 }
@@ -3330,11 +3327,10 @@
                             .mayUseInputMethod(mWindowAttributes.flags);
 
                     InputMethodManager imm = InputMethodManager.peekInstance();
+                    if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
+                        imm.onPreWindowFocus(mView, hasWindowFocus);
+                    }
                     if (mView != null) {
-                        if (hasWindowFocus && imm != null && mLastWasImTarget &&
-                                !isInLocalFocusMode()) {
-                            imm.startGettingWindowFocus(mView);
-                        }
                         mAttachInfo.mKeyDispatchState.reset();
                         mView.dispatchWindowFocusChanged(hasWindowFocus);
                         mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
@@ -3344,7 +3340,7 @@
                     // so all of the view state is set up correctly.
                     if (hasWindowFocus) {
                         if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
-                            imm.onWindowFocus(mView, mView.findFocus(),
+                            imm.onPostWindowFocus(mView, mView.findFocus(),
                                     mWindowAttributes.softInputMode,
                                     !mHasHadWindowFocus, mWindowAttributes.flags);
                         }
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 8dc49acd..5c8b023 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -25,60 +25,215 @@
  * View.onProvideStructure}.
  */
 public abstract class ViewStructure {
+    /**
+     * Set the identifier for this view.
+     *
+     * @param id The view's identifier, as per {@link View#getId View.getId()}.
+     * @param packageName The package name of the view's identifier, or null if there is none.
+     * @param typeName The type name of the view's identifier, or null if there is none.
+     * @param entryName The entry name of the view's identifier, or null if there is none.
+     */
     public abstract void setId(int id, String packageName, String typeName, String entryName);
 
+    /**
+     * Set the basic dimensions of this view.
+     *
+     * @param left The view's left position, in pixels relative to its parent's left edge.
+     * @param top The view's top position, in pixels relative to its parent's top edge.
+     * @param scrollX How much the view's x coordinate space has been scrolled, in pixels.
+     * @param scrollY How much the view's y coordinate space has been scrolled, in pixels.
+     * @param width The view's visible width, in pixels.  This is the width visible on screen,
+     * not the total data width of a scrollable view.
+     * @param height The view's visible height, in pixels.  This is the height visible on
+     * screen, not the total data height of a scrollable view.
+     */
     public abstract void setDimens(int left, int top, int scrollX, int scrollY, int width,
             int height);
 
+    /**
+     * Set the visibility state of this view, as per
+     * {@link View#getVisibility View.getVisibility()}.
+     */
     public abstract void setVisibility(int visibility);
 
     /** @hide */
     public abstract void setAssistBlocked(boolean state);
 
+    /**
+     * Set the enabled state of this view, as per {@link View#isEnabled View.isEnabled()}.
+     */
     public abstract void setEnabled(boolean state);
 
+    /**
+     * Set the clickable state of this view, as per {@link View#isClickable View.isClickable()}.
+     */
     public abstract void setClickable(boolean state);
 
+    /**
+     * Set the long clickable state of this view, as per
+     * {@link View#isLongClickable View.isLongClickable()}.
+     */
     public abstract void setLongClickable(boolean state);
 
+    /**
+     * Set the stylus button pressable state of this view, as per
+     * {@link View#isStylusButtonPressable View.isStylusButtonPressable()}.
+     */
     public abstract void setStylusButtonPressable(boolean state);
 
+    /**
+     * Set the focusable state of this view, as per {@link View#isFocusable View.isFocusable()}.
+     */
     public abstract void setFocusable(boolean state);
 
+    /**
+     * Set the focused state of this view, as per {@link View#isFocused View.isFocused()}.
+     */
     public abstract void setFocused(boolean state);
 
+    /**
+     * Set the accessibility focused state of this view, as per
+     * {@link View#isAccessibilityFocused View.isAccessibilityFocused()}.
+     */
     public abstract void setAccessibilityFocused(boolean state);
 
+    /**
+     * Set the checkable state of this view, such as whether it implements the
+     * {@link android.widget.Checkable} interface.
+     */
     public abstract void setCheckable(boolean state);
 
+    /**
+     * Set the checked state of this view, such as
+     * {@link android.widget.Checkable#isChecked Checkable.isChecked()}.
+     */
     public abstract void setChecked(boolean state);
 
+    /**
+     * Set the selected state of this view, as per {@link View#isSelected View.isSelected()}.
+     */
     public abstract void setSelected(boolean state);
 
+    /**
+     * Set the activated state of this view, as per {@link View#isActivated View.isActivated()}.
+     */
     public abstract void setActivated(boolean state);
 
+    /**
+     * Set the class name of the view, as per
+     * {@link View#getAccessibilityClassName View.getAccessibilityClassName()}.
+     */
     public abstract void setClassName(String className);
 
+    /**
+     * Set the content description of the view, as per
+     * {@link View#getContentDescription View.getContentDescription()}.
+     */
     public abstract void setContentDescription(CharSequence contentDescription);
 
+    /**
+     * Set the text that is associated with this view.  There is no selection
+     * associated with the text.  The text may have style spans to supply additional
+     * display and semantic information.
+     */
     public abstract void setText(CharSequence text);
+
+    /**
+     * Like {@link #setText(CharSequence)} but with an active selection
+     * extending from <var>selectionStart</var> through <var>selectionEnd</var>.
+     */
     public abstract void setText(CharSequence text, int selectionStart, int selectionEnd);
+
+    /**
+     * Set default global style of the text previously set with
+     * {@link #setText}, derived from the given TextPaint object.  Size, foreground color,
+     * background color, and style information will be extracted from the paint.
+     */
     public abstract void setTextPaint(TextPaint paint);
+
+    /**
+     * Explicitly set default global style information for text that was previously set with
+     * {@link #setText}.
+     *
+     * @param size The size, in pixels, of the text.
+     * @param fgColor The foreground color, packed as 0xAARRGGBB.
+     * @param bgColor The background color, packed as 0xAARRGGBB.
+     * @param style Style flags, as defined by {@link android.app.AssistStructure.ViewNode}.
+     */
+    public abstract void setTextStyle(int size, int fgColor, int bgColor, int style);
+
+    /**
+     * Set optional hint text associated with this view; this is for example the text that is
+     * shown by an EditText when it is empty to indicate to the user the kind of text to input.
+     */
     public abstract void setHint(CharSequence hint);
 
+    /**
+     * Retrieve the last {@link #setText(CharSequence)}.
+     */
     public abstract CharSequence getText();
+
+    /**
+     * Retrieve the last selection start set by {@link #setText(CharSequence, int, int)}.
+     */
     public abstract int getTextSelectionStart();
+
+    /**
+     * Retrieve the last selection end set by {@link #setText(CharSequence, int, int)}.
+     */
     public abstract int getTextSelectionEnd();
+
+    /**
+     * Retrieve the last hint set by {@link #setHint}.
+     */
     public abstract CharSequence getHint();
 
+    /**
+     * Get extra data associated with this view structure; the returned Bundle is mutable,
+     * allowing you to view and modify its contents.  Keys placed in the Bundle should use
+     * an appropriate namespace prefix (such as com.google.MY_KEY) to avoid conflicts.
+     */
     public abstract Bundle getExtras();
+
+    /**
+     * Returns true if {@link #getExtras} has been used to create extra content.
+     */
     public abstract boolean hasExtras();
 
+    /**
+     * Set the number of children of this view, which defines the range of indices you can
+     * use with {@link #newChild} and {@link #asyncNewChild}.  Calling this method again
+     * resets all of the child state of the view, removing any children that had previously
+     * been added.
+     */
     public abstract void setChildCount(int num);
+
+    /**
+     * Return the child count as set by {@link #setChildCount}.
+     */
     public abstract int getChildCount();
+
+    /**
+     * Create a new child {@link ViewStructure} in this view, putting into the list of
+     * children at <var>index</var>.
+     * @return Returns an fresh {@link ViewStructure} ready to be filled in.
+     */
     public abstract ViewAssistStructure newChild(int index);
 
+    /**
+     * Like {@link #newChild}, but allows the caller to asynchronously populate the returned
+     * child.  It can transfer the returned {@link ViewStructure} to another thread for it
+     * to build its content (and children etc).  Once done, some thread must call
+     * {@link #asyncCommit} to tell the containing {@link ViewStructure} that the async
+     * population is done.
+     * @return Returns an fresh {@link ViewStructure} ready to be filled in.
+     */
     public abstract ViewAssistStructure asyncNewChild(int index);
+
+    /**
+     * Call when done populating a {@link ViewStructure} returned by
+     * {@link #asyncNewChild}.
+     */
     public abstract void asyncCommit();
 
     /** @hide */
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 568e160..824b434 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1289,14 +1289,14 @@
 
     void focusInLocked(View view) {
         if (DEBUG) Log.v(TAG, "focusIn: " + view);
-        
+
         if (mCurRootView != view.getRootView()) {
             // This is a request from a window that isn't in the window with
             // IME focus, so ignore it.
             if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
             return;
         }
-        
+
         mNextServedView = view;
         scheduleCheckFocusLocked(view);
     }
@@ -1392,7 +1392,7 @@
      * Called by ViewAncestor when its window gets input focus.
      * @hide
      */
-    public void onWindowFocus(View rootView, View focusedView, int softInputMode,
+    public void onPostWindowFocus(View rootView, View focusedView, int softInputMode,
             boolean first, int windowFlags) {
         boolean forceNewFocus = false;
         synchronized (mH) {
@@ -1441,14 +1441,27 @@
             }
         }
     }
-    
+
     /** @hide */
-    public void startGettingWindowFocus(View rootView) {
+    public void onPreWindowFocus(View rootView, boolean hasWindowFocus) {
         synchronized (mH) {
-            mCurRootView = rootView;
+            if (rootView == null) {
+                mCurRootView = null;
+            } if (hasWindowFocus) {
+                mCurRootView = rootView;
+            } else if (rootView == mCurRootView) {
+                // If the mCurRootView is losing window focus, release the strong reference to it
+                // so as not to prevent it from being garbage-collected.
+                mCurRootView = null;
+            } else {
+                if (DEBUG) {
+                    Log.v(TAG, "Ignoring onPreWindowFocus()."
+                            + " mCurRootView=" + mCurRootView + " rootView=" + rootView);
+                }
+            }
         }
     }
-    
+
     /**
      * Report the current selection range.
      *
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index ab6a2f9..b3b95f8 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -154,9 +154,9 @@
     }
 
     public void showSoftInput() {
-        mInput.startGettingWindowFocus(mEditText.getRootView());
-        mInput.focusIn(mEditText);
-        mInput.showSoftInput(mEditText, 0);
+        if (mEditText.requestFocus()) {
+            mInput.showSoftInput(mEditText, 0);
+        }
     }
 
     public void updateMatchCount(int matchIndex, int matchCount, boolean isEmptyFind) {
diff --git a/core/java/android/webkit/ViewAssistStructure.java b/core/java/android/webkit/ViewAssistStructure.java
index 6f7a645..bbaceee 100644
--- a/core/java/android/webkit/ViewAssistStructure.java
+++ b/core/java/android/webkit/ViewAssistStructure.java
@@ -137,6 +137,11 @@
     }
 
     @Override
+    public void setTextStyle(int size, int fgColor, int bgColor, int style) {
+        mV.setTextStyle(size, fgColor, bgColor, style);
+    }
+
+    @Override
     public  void setHint(CharSequence hint) {
         mV.setHint(hint);
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c829783..d558c7b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -233,6 +233,24 @@
 
     final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
 
+    private final Runnable mHideFloatingToolbar = new Runnable() {
+        @Override
+        public void run() {
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT);
+            }
+        }
+    };
+
+    private final Runnable mShowFloatingToolbar = new Runnable() {
+        @Override
+        public void run() {
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.snooze(0);  // snooze off.
+            }
+        }
+    };
+
     Editor(TextView textView) {
         mTextView = textView;
         // Synchronize the filter list, which places the undo input filter at the end.
@@ -358,6 +376,9 @@
             mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
         }
 
+        mTextView.removeCallbacks(mHideFloatingToolbar);
+        mTextView.removeCallbacks(mShowFloatingToolbar);
+
         destroyDisplayListsData();
 
         if (mSpellChecker != null) {
@@ -1169,6 +1190,8 @@
     }
 
     void onTouchEvent(MotionEvent event) {
+        updateFloatingToolbarVisibility(event);
+
         if (hasSelectionController()) {
             getSelectionController().onTouchEvent(event);
         }
@@ -1189,6 +1212,37 @@
         }
     }
 
+    private void updateFloatingToolbarVisibility(MotionEvent event) {
+        if (mSelectionActionMode != null) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_MOVE:
+                    hideFloatingToolbar();
+                    break;
+                case MotionEvent.ACTION_UP:  // fall through
+                case MotionEvent.ACTION_CANCEL:
+                    showFloatingToolbar();
+            }
+        }
+    }
+
+    private void hideFloatingToolbar() {
+        if (mSelectionActionMode != null) {
+            mTextView.removeCallbacks(mShowFloatingToolbar);
+            // Delay the "hide" a little bit just in case a "show" will happen almost immediately.
+            mTextView.postDelayed(mHideFloatingToolbar, 100);
+        }
+    }
+
+    private void showFloatingToolbar() {
+        if (mSelectionActionMode != null) {
+            mTextView.removeCallbacks(mHideFloatingToolbar);
+            // Delay "show" so it doesn't interfere with click confirmations
+            // or double-clicks that could "dismiss" the floating toolbar.
+            int delay = ViewConfiguration.getDoubleTapTimeout();
+            mTextView.postDelayed(mShowFloatingToolbar, delay);
+        }
+    }
+
     public void beginBatchEdit() {
         mInBatchEditControllers = true;
         final InputMethodState ims = mInputMethodState;
@@ -3661,6 +3715,8 @@
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
+            updateFloatingToolbarVisibility(ev);
+
             switch (ev.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
                     startTouchUpFilter(getCurrentCursorOffset());
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5acd79f..a93e7ef 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -24,6 +24,7 @@
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.XmlRes;
+import android.app.Activity;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
@@ -1465,16 +1466,22 @@
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == PROCESS_TEXT_REQUEST_CODE) {
-            CharSequence result = data != null
-                    ? data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)
-                    : "";
-            if (isTextEditable()) {
-                replaceSelectionWithText(result);
-            } else {
-                if (result.length() > 0) {
-                    Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG).show();
+            if (resultCode == Activity.RESULT_OK && data != null) {
+                CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
+                if (result != null) {
+                    if (isTextEditable()) {
+                        replaceSelectionWithText(result);
+                    } else {
+                        if (result.length() > 0) {
+                            Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
+                                .show();
+                        }
+                    }
                 }
             }
+            if (mEditor.hasSelectionController()) {
+                mEditor.startSelectionActionModeWithSelection();
+            }
         }
     }
 
@@ -9279,7 +9286,6 @@
 
     void replaceSelectionWithText(CharSequence text) {
         ((Editable) mText).replace(getSelectionStart(), getSelectionEnd(), text);
-        mEditor.startSelectionActionModeWithSelection();
     }
 
     /**
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
index 5c0a888..67ee085 100644
--- a/core/java/com/android/internal/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -29,7 +29,7 @@
  */
 public class AlsaCardsParser {
     private static final String TAG = "AlsaCardsParser";
-    protected static final boolean DEBUG = true;
+    protected static final boolean DEBUG = false;
 
     private static final String kCardsFilePath = "/proc/asound/cards";
 
diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
index 6ff0304..23a8bd7 100644
--- a/core/java/com/android/internal/app/ProcessMap.java
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -39,14 +39,16 @@
         return value;
     }
     
-    public void remove(String name, int uid) {
+    public E remove(String name, int uid) {
         SparseArray<E> uids = mMap.get(name);
         if (uids != null) {
-            uids.remove(uid);
+            final E old = uids.removeReturnOld(uid);
             if (uids.size() == 0) {
                 mMap.remove(name);
             }
+            return old;
         }
+        return null;
     }
     
     public ArrayMap<String, SparseArray<E>> getMap() {
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index 65dc743..b9a75d3 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -208,6 +208,7 @@
     public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
     public static final int APPLICATIONS_HIGH_POWER_APPS = 184;
     public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185;
+    public static final int APPLICATIONS_MANAGE_ASSIST = 186;
 
     //aliases
     public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY;
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 1bcc7a0..58ae853 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -33,16 +33,4 @@
         }
         return 0;
     }
-
-    /**
-     * Get whether a device has has a round screen.
-     */
-    public static boolean getWindowIsRound(Resources resources) {
-        if (IS_EMULATOR) {
-            return SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
-        } else {
-            return resources.getBoolean(
-                    com.android.internal.R.bool.config_windowIsRound);
-        }
-    }
 }
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index c3f4da7..0195208 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -30,6 +30,9 @@
 
 public class FloatingActionMode extends ActionMode {
 
+    private static final int MAX_SNOOZE_TIME = 3000;
+    private static final int MOVING_HIDE_DELAY = 300;
+
     private final Context mContext;
     private final ActionMode.Callback2 mCallback;
     private final MenuBuilder mMenu;
@@ -37,13 +40,29 @@
     private final Rect mContentRectOnWindow;
     private final Rect mPreviousContentRectOnWindow;
     private final int[] mViewPosition;
+    private final Rect mViewRect;
+    private final Rect mScreenRect;
     private final View mOriginatingView;
+
+    private final Runnable mMovingOff = new Runnable() {
+        public void run() {
+            mFloatingToolbarVisibilityHelper.setMoving(false);
+        }
+    };
+
+    private final Runnable mSnoozeOff = new Runnable() {
+        public void run() {
+            mFloatingToolbarVisibilityHelper.setSnoozed(false);
+        }
+    };
+
     private FloatingToolbar mFloatingToolbar;
+    private FloatingToolbarVisibilityHelper mFloatingToolbarVisibilityHelper;
 
     public FloatingActionMode(
             Context context, ActionMode.Callback2 callback, View originatingView) {
-        mContext = context;
-        mCallback = callback;
+        mContext = Preconditions.checkNotNull(context);
+        mCallback = Preconditions.checkNotNull(callback);
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
@@ -51,7 +70,10 @@
         mContentRectOnWindow = new Rect();
         mPreviousContentRectOnWindow = new Rect();
         mViewPosition = new int[2];
-        mOriginatingView = originatingView;
+        mViewRect = new Rect();
+        mScreenRect = new Rect();
+        mOriginatingView = Preconditions.checkNotNull(originatingView);
+        mOriginatingView.getLocationInWindow(mViewPosition);
     }
 
     public void setFloatingToolbar(FloatingToolbar floatingToolbar) {
@@ -63,6 +85,7 @@
                         return mCallback.onActionItemClicked(FloatingActionMode.this, item);
                     }
                 });
+        mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
     }
 
     @Override
@@ -82,7 +105,7 @@
 
     @Override
     public void invalidate() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mCallback.onPrepareActionMode(this, mMenu);
         mFloatingToolbar.updateLayout();
         invalidateContentRect();
@@ -90,32 +113,79 @@
 
     @Override
     public void invalidateContentRect() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
         repositionToolbar();
     }
 
     public void updateViewLocationInWindow() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mOriginatingView.getLocationInWindow(mViewPosition);
+        mViewRect.set(
+                mViewPosition[0],
+                mViewPosition[1],
+                mViewPosition[0] + mOriginatingView.getWidth(),
+                mViewPosition[1] + mOriginatingView.getHeight());
         repositionToolbar();
     }
 
     private void repositionToolbar() {
+        checkToolbarInitialized();
         mContentRectOnWindow.set(
                 mContentRect.left + mViewPosition[0],
                 mContentRect.top + mViewPosition[1],
                 mContentRect.right + mViewPosition[0],
                 mContentRect.bottom + mViewPosition[1]);
         if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
+            if (!mPreviousContentRectOnWindow.isEmpty()) {
+                notifyContentRectMoving();
+            }
             mFloatingToolbar.setContentRect(mContentRectOnWindow);
             mFloatingToolbar.updateLayout();
         }
         mPreviousContentRectOnWindow.set(mContentRectOnWindow);
+
+        if (isContentRectWithinBounds()) {
+            mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
+        } else {
+            mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
+        }
+    }
+
+    private boolean isContentRectWithinBounds() {
+       mScreenRect.set(
+           0,
+           0,
+           mContext.getResources().getDisplayMetrics().widthPixels,
+           mContext.getResources().getDisplayMetrics().heightPixels);
+
+       return Rect.intersects(mContentRectOnWindow, mScreenRect)
+           && Rect.intersects(mContentRectOnWindow, mViewRect);
+    }
+
+    private void notifyContentRectMoving() {
+        mOriginatingView.removeCallbacks(mMovingOff);
+        mFloatingToolbarVisibilityHelper.setMoving(true);
+        mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+    }
+
+    @Override
+    public void snooze(int snoozeTime) {
+        checkToolbarInitialized();
+        snoozeTime = Math.min(MAX_SNOOZE_TIME, snoozeTime);
+        mOriginatingView.removeCallbacks(mSnoozeOff);
+        if (snoozeTime <= 0) {
+            mSnoozeOff.run();
+        } else {
+            mFloatingToolbarVisibilityHelper.setSnoozed(true);
+            mOriginatingView.postDelayed(mSnoozeOff, snoozeTime);
+        }
     }
 
     @Override
     public void finish() {
+        checkToolbarInitialized();
+        reset();
         mCallback.onDestroyActionMode(this);
     }
 
@@ -144,4 +214,56 @@
         return new MenuInflater(mContext);
     }
 
+    /**
+     * @throws IlllegalStateException
+     */
+    private void checkToolbarInitialized() {
+        Preconditions.checkState(mFloatingToolbar != null);
+        Preconditions.checkState(mFloatingToolbarVisibilityHelper != null);
+    }
+
+    private void reset() {
+        mOriginatingView.removeCallbacks(mMovingOff);
+        mOriginatingView.removeCallbacks(mSnoozeOff);
+    }
+
+
+    /**
+     * A helper that shows/hides the floating toolbar depending on certain states.
+     */
+    private static final class FloatingToolbarVisibilityHelper {
+
+        private final FloatingToolbar mToolbar;
+
+        private boolean mSnoozed;
+        private boolean mMoving;
+        private boolean mOutOfBounds;
+
+        public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
+            mToolbar = Preconditions.checkNotNull(toolbar);
+        }
+
+        public void setSnoozed(boolean snoozed) {
+            mSnoozed = snoozed;
+            updateToolbarVisibility();
+        }
+
+        public void setMoving(boolean moving) {
+            mMoving = moving;
+            updateToolbarVisibility();
+        }
+
+        public void setOutOfBounds(boolean outOfBounds) {
+            mOutOfBounds = outOfBounds;
+            updateToolbarVisibility();
+        }
+
+        private void updateToolbarVisibility() {
+            if (mSnoozed || mMoving || mOutOfBounds) {
+                mToolbar.hide();
+            } else if (mToolbar.isHidden()) {
+                mToolbar.show();
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index fdc3547..b7a53b0 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -357,7 +357,7 @@
             mShowAnimation = createGrowFadeInFromBottom(mContentContainer);
             mDismissAnimation = createShrinkFadeOutFromBottomAnimation(
                     mContentContainer,
-                    0,
+                    150,  // startDelay
                     new AnimatorListenerAdapter() {
                         @Override
                         public void onAnimationEnd(Animator animation) {
@@ -367,7 +367,7 @@
                     });
             mHideAnimation = createShrinkFadeOutFromBottomAnimation(
                     mContentContainer,
-                    150,
+                    0,  // startDelay
                     new AnimatorListenerAdapter() {
                         @Override
                         public void onAnimationEnd(Animator animation) {
diff --git a/core/java/com/android/internal/widget/TextViewInputDisabler.java b/core/java/com/android/internal/widget/TextViewInputDisabler.java
new file mode 100644
index 0000000..fb0b3b9
--- /dev/null
+++ b/core/java/com/android/internal/widget/TextViewInputDisabler.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.internal.widget;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.widget.TextView;
+
+/**
+ * Helper class to disable input on a TextView. The input is disabled by swapping in an InputFilter
+ * that discards all changes. Use with care if you have customized InputFilter on the target
+ * TextView.
+ */
+public class TextViewInputDisabler {
+    private TextView mTextView;
+    private InputFilter[] mDefaultFilters;
+    private InputFilter[] mNoInputFilters = new InputFilter[] {
+            new InputFilter () {
+                @Override
+                public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+                        int dstart, int dend) {
+                    return "";
+                }
+            }
+    };
+
+    public TextViewInputDisabler(TextView textView) {
+        mTextView = textView;
+        mDefaultFilters = mTextView.getFilters();
+    }
+
+    public void setInputEnabled(boolean enabled) {
+        mTextView.setFilters(enabled ? mDefaultFilters : mNoInputFilters);
+    }
+}
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index cf02e39..3bab2df 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -212,10 +212,14 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    SkRegion* region = new SkRegion;
-    size_t size = p->readInt32();
-    size_t actualSize = region->readFromMemory(p->readInplace(size), size);
+    const size_t size = p->readInt32();
+    const void* regionData = p->readInplace(size);
+    if (regionData == nullptr) {
+        return 0;
+    }
 
+    SkRegion* region = new SkRegion;
+    size_t actualSize = region->readFromMemory(regionData, size);
     if (size != actualSize) {
         delete region;
         return 0;
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 60e8ed0..fada7ac2 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -291,6 +291,11 @@
     return (jboolean) !protectFromVpn(socket);
 }
 
+static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
+{
+    return (jboolean) !queryUserAccess(uid, netId);
+}
+
 
 // ----------------------------------------------------------------------------
 
@@ -311,6 +316,7 @@
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
     { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
+    { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
 };
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0d7d868..21c4a8d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1035,9 +1035,6 @@
         <!-- The color applied to framework switch thumbs in their normal state. -->
         <attr name="colorSwitchThumbNormal" format="color" />
 
-        <!-- @hide The background used by framework controls. -->
-        <attr name="controlBackground" format="reference" />
-
         <!-- The color applied to the edge effect on scrolling containers. -->
         <attr name="colorEdgeEffect" format="color" />
 
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index c2371ee..165d1f8 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -572,16 +572,16 @@
     <style name="Widget.Material.CompoundButton" parent="Widget.CompoundButton"/>
 
     <style name="Widget.Material.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.Star" parent="Widget.CompoundButton.Star">
         <item name="button">@drawable/btn_star_material</item>
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.Switch">
@@ -590,7 +590,7 @@
         <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item>
         <item name="textOn">@string/capital_on</item>
         <item name="textOff">@string/capital_off</item>
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
         <item name="showText">false</item>
     </style>
 
@@ -727,7 +727,7 @@
         <item name="paddingStart">16dip</item>
         <item name="paddingEnd">16dip</item>
         <item name="mirrorForRtl">true</item>
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
     </style>
 
     <style name="Widget.Material.RatingBar" parent="Widget.RatingBar">
@@ -809,7 +809,7 @@
     </style>
 
     <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Material">
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
         <item name="minWidth">56dp</item>
         <item name="scaleType">center</item>
         <item name="paddingStart">@dimen/action_bar_navigation_padding_start_material</item>
@@ -866,7 +866,7 @@
     </style>
 
     <style name="Widget.Material.ActionButton.CloseMode">
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
     </style>
 
     <style name="Widget.Material.ActionButton.Overflow">
@@ -962,7 +962,7 @@
     </style>
 
     <style name="Widget.Material.MediaRouteButton">
-        <item name="background">?attr/controlBackground</item>
+        <item name="background">@drawable/control_background_material</item>
         <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_material</item>
         <item name="minWidth">56dp</item>
         <item name="minHeight">48dp</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dee34cc..6124b5b 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,7 +294,6 @@
   <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
-  <java-symbol type="bool" name="config_windowIsRound" />
   <java-symbol type="bool" name="config_hasRecents" />
   <java-symbol type="bool" name="config_windowShowCircularMask" />
   <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index f02fed1..3f8071f 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -390,8 +390,6 @@
         <item name="colorControlHighlight">@color/ripple_material_dark</item>
         <item name="colorButtonNormal">@color/btn_default_material_dark</item>
         <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
-
-        <item name="controlBackground">@drawable/control_background_material</item>
     </style>
 
     <!-- Material theme (light version). -->
@@ -740,8 +738,6 @@
         <item name="colorControlHighlight">@color/ripple_material_light</item>
         <item name="colorButtonNormal">@color/btn_default_material_light</item>
         <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
-
-        <item name="controlBackground">@drawable/control_background_material</item>
     </style>
 
     <!-- Variant of the material (light) theme that has a solid (opaque) action bar
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 0634281..a7bebad 100644
--- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -26,9 +26,11 @@
 import libcore.util.HexEncoding;
 
 import java.net.InetAddress;
+import java.net.Inet4Address;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 import junit.framework.TestCase;
 
 
@@ -133,7 +135,7 @@
     public static final byte[] RTM_GETNEIGH_RESPONSE =
             HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
 
-    public void testParseRtNetlinkNeighborRtmDelNeigh() {
+    public void testParseRtmDelNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -159,7 +161,7 @@
         assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
     }
 
-    public void testParseRtNetlinkNeighborRtmNewNeigh() {
+    public void testParseRtmNewNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -185,7 +187,7 @@
         assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
     }
 
-    public void testParseRtNetlinkNeighborRtmGetNeighResponse() {
+    public void testParseRtmGetNeighResponse() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
 
@@ -208,4 +210,48 @@
         // TODO: add more detailed spot checks.
         assertEquals(14, messageCount);
     }
+
+    public void testCreateRtmNewNeighMessage() {
+        final int seqNo = 2635;
+        final int ifIndex = 14;
+        final byte[] llAddr =
+                new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
+
+        // Hexadecimal representation of our created packet.
+        final String expectedNewNeighHex =
+                // struct nlmsghdr
+                "30000000" +     // length = 48
+                "1c00" +         // type = 28 (RTM_NEWNEIGH)
+                "0101" +         // flags (NLM_F_REQUEST | NLM_F_REPLACE)
+                "4b0a0000" +     // seqno
+                "00000000" +     // pid (0 == kernel)
+                // struct ndmsg
+                "02" +           // family
+                "00" +           // pad1
+                "0000" +         // pad2
+                "0e000000" +     // interface index (14)
+                "0800" +         // NUD state (0x08 == NUD_DELAY)
+                "00" +           // flags
+                "00" +           // type
+                // struct nlattr: NDA_DST
+                "0800" +         // length = 8
+                "0100" +         // type (1 == NDA_DST, for neighbor messages)
+                "7f000001" +     // IPv4 address (== 127.0.0.1)
+                // struct nlattr: NDA_LLADDR
+                "0a00" +         // length = 10
+                "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
+                "010203040506" + // MAC Address (== 01:02:03:04:05:06)
+                "0000";          // padding, for 4 byte alignment
+        final byte[] expectedNewNeigh =
+                HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
+
+        final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
+            seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
+        if (!Arrays.equals(expectedNewNeigh, bytes)) {
+            assertEquals(expectedNewNeigh.length, bytes.length);
+            for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
+                assertEquals(expectedNewNeigh[i], bytes[i]);
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index af6df1a..0b94f8b 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,9 +16,13 @@
 
 package android.widget;
 
+import android.app.Activity;
+import android.content.Intent;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.GetChars;
+import android.text.Selection;
+import android.text.Spannable;
 
 /**
  * TextViewTest tests {@link TextView}.
@@ -54,4 +58,66 @@
         assertEquals('o', c2[4]);
         assertEquals('\0', c2[5]);
     }
+
+    public void testProcessTextActivityResultNonEditable() {
+        TextView tv = new TextView(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection((Spannable) tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+
+        // This is a TextView, which can't be modified. Hence no change should have been made.
+        assertEquals(originalText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityResultEditable() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+
+        assertEquals(newText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityResultCancel() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_CANCELED, data);
+
+        assertEquals(originalText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityNoData() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, null);
+
+        assertEquals(originalText, tv.getText().toString());
+    }
 }
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 0aa588b..5857de0 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -35,14 +35,14 @@
 <familyset>
     <family>
         <fileset>
-            <file variant="elegant">NotoNaskh-Regular.ttf</file>
-            <file variant="elegant">NotoNaskh-Bold.ttf</file>
+            <file variant="elegant">NotoNaskhArabic-Regular.ttf</file>
+            <file variant="elegant">NotoNaskhArabic-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file variant="compact">NotoNaskhUI-Regular.ttf</file>
-            <file variant="compact">NotoNaskhUI-Bold.ttf</file>
+            <file variant="compact">NotoNaskhArabicUI-Regular.ttf</file>
+            <file variant="compact">NotoNaskhArabicUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
@@ -387,6 +387,11 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansTibetan-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansTifinagh-Regular.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index f903aab..62da0ff 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -94,12 +94,12 @@
 
     <!-- fallback fonts -->
     <family variant="elegant">
-        <font weight="400" style="normal">NotoNaskh-Regular.ttf</font>
-        <font weight="700" style="normal">NotoNaskh-Bold.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
     </family>
     <family variant="compact">
-        <font weight="400" style="normal">NotoNaskhUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoNaskhUI-Bold.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
@@ -320,6 +320,9 @@
         <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
     </family>
     <family>
diff --git a/docs/html/preview/images/bugs.png b/docs/html/preview/images/bugs.png
deleted file mode 100644
index 46adf05..0000000
--- a/docs/html/preview/images/bugs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/dev-prev.png b/docs/html/preview/images/dev-prev.png
deleted file mode 100644
index eae6ede..0000000
--- a/docs/html/preview/images/dev-prev.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/m-preview-timeline.png b/docs/html/preview/images/m-preview-timeline.png
index a065c21..bda0b46 100644
--- a/docs/html/preview/images/m-preview-timeline.png
+++ b/docs/html/preview/images/m-preview-timeline.png
Binary files differ
diff --git a/docs/html/preview/images/updates.png b/docs/html/preview/images/updates.png
deleted file mode 100644
index f165c5a..0000000
--- a/docs/html/preview/images/updates.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index 4005a05..20963f5 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -5,6 +5,7 @@
   <div id="qv">
     <h2>In this document</h2>
     <ol>
+      <li><a href="#SecurityFeatures">Security Features</a></li>
       <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li>
       <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider
       </a></li>
@@ -31,7 +32,8 @@
   keystore, they can be used for cryptographic operations with the key material
   remaining non-exportable. Moreover, it offers facilities to restrict when and
   how keys can be used, such as requiring user authentication for key use or
-  restricting encryption keys to be used only in certain block modes.</p>
+  restricting encryption keys to be used only in certain block modes. See
+  <a href="#SecurityFeatures">Security Features</a> section for more information.</p>
 
 <p>The Keystore system is used by the {@link
   android.security.KeyChain} API as well as the Android
@@ -39,6 +41,67 @@
   (API level 18). This document goes over when and how to use the
   Android Keystore provider.</p>
 
+
+<h2 id="SecurityFeatures">Security Features</h2>
+
+Android Keystore system protects key material from unauthorized use. Firstly, Android Keystore
+mitigates unauthorized use of key material outside of the Android device by preventing extraction of
+the key material from application processes and from the Android device as a whole. Secondly,
+Android KeyStore mitigates unauthorized use of key material on the Android device by making apps
+specify authorized uses of their keys and then enforcing these restrictions.
+
+<h3 id="ExtractionPrevention">Extraction Prevention</h3>
+
+Key material of Android Keystore keys is protected from extraction using two security measures:
+<ul>
+<li>Key material never enters the application process. When an application performs cryptographic
+  operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to
+  be signed or verified are fed to a system process which carries out the cryptographic operations.
+  If the app's process is compromised, the attacker may be able to use the app's keys but will not
+  be able to extract their key material (for example, to be used outside of the Android device).
+  </li>
+<li>Key material may be bound to the secure hardware (e.g., Trusted Execution Environment (TEE),
+  Secure Element (SE)) of the Android device. When this feature is enabled for a key, its key
+  material is never exposed outside of secure hardware. If the Android OS is compromised or an
+  attacker can read the device's internal storage, the attacker may be able to use any app's Android
+  Keystore keys on the Android device, but not extract them from the device. This feature is enabled
+  only if the device's secure hardware supports the particular combination of key algorithm, block
+  modes, padding schemes, and digests with which the key is authorized to be used. To check whether
+  the feature is enabled for a key, obtain a {@link android.security.keystore.KeyInfo} for the key
+  and inspect the return value of
+  {@link android.security.keystore.KeyInfo#isInsideSecureHardware() KeyInfo.isInsideSecurityHardware()}.
+  </li>
+</ul>
+
+<h3 id="KeyUseAuthorizations">Key Use Authorizations</h3>
+
+To mitigate unauthorized use of keys on the Android device, Android Keystore lets apps specify
+authorized uses of their keys when generating or importing the keys. Once a key is generated or
+imported, its authorizations can not be changed. Authorizations are then enforced by the Android
+Keystore whenever the key is used.
+
+<p>Supported key use authorizations fall into the following categories:
+<ul>
+<li><em>cryptography</em>: authorized key algorithm, operations or purposes (encrypt, decrypt, sign,
+  verify), padding schemes, block modes, digests with which the key can be used</li>
+<li><em>temporal validity interval</em>: interval of time during which the key is authorized for
+  use</li>
+<li><em>user authentication</em>: the key can only be used if the user has been authenticated
+  recently enough. See <a href="#UserAuthentication">Requiring User Authentication For Key Use</a>.
+  </li>
+</ul>
+
+<p>As an additional security measure, for keys whose key material is inside secure hardware (see
+  {@link android.security.keystore.KeyInfo#isInsideSecureHardware() KeyInfo.isInsideSecurityHardware()})
+  some key use authorizations may be enforced by secure hardware, depending on the Android device.
+  Cryptographic and user authentication authorizations are likely to be enforced by secure hardware.
+  Temporal validity interval authorizations are unlikely to be enforced by the secure hardware
+  because it normally does not have an independent secure real-time clock.
+
+<p>Whether a key's user authentication authorization is enforced by the secure hardware can be
+  queried using
+  {@link android.security.keystore.KeyInfo#isUserAuthenticationRequirementEnforcedBySecureHardware() KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()}.
+
 <h2 id="WhichShouldIUse">Choosing Between a Keychain or the
 Android Keystore Provider</h2>
 
@@ -129,7 +192,7 @@
   for use as soon as the user unlocks the secure lock screen or confirms their secure lock screen
   credentials using the {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent}
   flow. Each key specifies for how long the authorization remains valid for that key. Such keys
-  can only be generated or imported if the secure lock screen is enabled (see {@link android.app.KeyguardManager#isDeviceSecure()}).
+  can only be generated or imported if the secure lock screen is enabled (see {@link android.app.KeyguardManager#isDeviceSecure() KeyguardManager.isDeviceSecure()}).
   These keys become permanently invalidated once the secure lock screen is disabled or forcibly
   reset (e.g. by a Device Admin).</li>
 <li>User authentication is required for every use of the key. In this mode, a specific operation
diff --git a/keystore/java/android/security/keystore/AndroidKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
similarity index 96%
rename from keystore/java/android/security/keystore/AndroidKeyPairGeneratorSpi.java
rename to keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 2c393fd..4b45fd7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -52,19 +52,19 @@
  * <p>
  * This class can not be directly instantiated and must instead be used via the
  * {@link KeyPairGenerator#getInstance(String)
- * KeyPairGenerator.getInstance("AndroidKeyPairGenerator")} API.
+ * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
  *
- * {@hide}
+ * @hide
  */
-public abstract class AndroidKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
+public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
 
-    public static class RSA extends AndroidKeyPairGeneratorSpi {
+    public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
         public RSA() {
             super(KeyProperties.KEY_ALGORITHM_RSA);
         }
     }
 
-    public static class EC extends AndroidKeyPairGeneratorSpi {
+    public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
         public EC() {
             super(KeyProperties.KEY_ALGORITHM_EC);
         }
@@ -94,7 +94,7 @@
     private int mKeyType;
     private int mKeySize;
 
-    protected AndroidKeyPairGeneratorSpi(@KeyProperties.KeyAlgorithmEnum String algorithm) {
+    protected AndroidKeyStoreKeyPairGeneratorSpi(@KeyProperties.KeyAlgorithmEnum String algorithm) {
         mAlgorithm = algorithm;
     }
 
@@ -283,7 +283,8 @@
 
     @Override
     public void initialize(int keysize, SecureRandom random) {
-        throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator");
+        throw new IllegalArgumentException(
+                "cannot specify keysize with AndroidKeyStore KeyPairGenerator");
     }
 
     @Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index b20a122..649a515 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -49,8 +49,8 @@
         put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
 
         // java.security.KeyPairGenerator
-        put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyPairGeneratorSpi$EC");
-        put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyPairGeneratorSpi$RSA");
+        put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
+        put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
 
         // javax.crypto.KeyGenerator
         put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
@@ -111,6 +111,7 @@
      *
      * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
      *         by AndroidKeyStore provider.
+     * @throws IllegalStateException if the provided primitive is not initialized.
      */
     public static long getKeyStoreOperationHandle(Object cryptoPrimitive) {
         if (cryptoPrimitive == null) {
@@ -118,15 +119,17 @@
         }
         Object spi;
         if (cryptoPrimitive instanceof Mac) {
-            spi = ((Mac) cryptoPrimitive).getSpi();
+            spi = ((Mac) cryptoPrimitive).getCurrentSpi();
         } else if (cryptoPrimitive instanceof Cipher) {
-            spi = ((Cipher) cryptoPrimitive).getSpi();
+            spi = ((Cipher) cryptoPrimitive).getCurrentSpi();
         } else {
             throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive);
         }
-        if (!(spi instanceof KeyStoreCryptoOperation)) {
+        if (spi == null) {
+            throw new IllegalStateException("Crypto primitive not initialized");
+        } else if (!(spi instanceof KeyStoreCryptoOperation)) {
             throw new IllegalArgumentException(
-                    "Crypto primitive not backed by AndroidKeyStore: " + cryptoPrimitive
+                    "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive
                     + ", spi: " + spi);
         }
         return ((KeyStoreCryptoOperation) spi).getOperationHandle();
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
index 6d0a06b..d822cb2 100644
--- a/libs/hwui/utils/RingBuffer.h
+++ b/libs/hwui/utils/RingBuffer.h
@@ -31,7 +31,7 @@
     RingBuffer() {}
     ~RingBuffer() {}
 
-    constexpr size_t capacity() { return SIZE; }
+    constexpr size_t capacity() const { return SIZE; }
     size_t size() { return mCount; }
 
     T& next() {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4526839..0f1be6b 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -724,6 +725,26 @@
                 return USAGE_UNKNOWN;
         }
     }
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
+     * Returns the stream type matching the given attributes for volume control.
+     * Use this method to derive the stream type needed to configure the volume
+     * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
+     * <BR>Do not use this method to set the stream type on an audio player object
+     * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
+     * @param aa non-null AudioAttributes.
+     * @return a valid stream type for <code>Activity</code> or stream volume control that matches
+     *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
+     *     match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
+     *     for {@link AudioManager#setStreamVolume(int, int, int)}.
+     */
+    public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
+        if (aa == null) {
+            throw new IllegalArgumentException("Invalid null audio attributes");
+        }
+        return toVolumeStreamType(true /*fromGetVolumeControlStream*/, aa);
+    }
 
     /**
      * @hide
@@ -732,13 +753,19 @@
      * @param aa non-null AudioAttributes.
      * @return a valid stream type for volume control that matches the attributes.
      */
-    public static int toLegacyStreamType(AudioAttributes aa) {
+    public static int toLegacyStreamType(@NonNull AudioAttributes aa) {
+        return toVolumeStreamType(false /*fromGetVolumeControlStream*/, aa);
+    }
+
+    private static int toVolumeStreamType(boolean fromGetVolumeControlStream, AudioAttributes aa) {
         // flags to stream type mapping
         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
-            return AudioSystem.STREAM_SYSTEM_ENFORCED;
+            return fromGetVolumeControlStream ?
+                    AudioSystem.STREAM_SYSTEM : AudioSystem.STREAM_SYSTEM_ENFORCED;
         }
         if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) {
-            return AudioSystem.STREAM_BLUETOOTH_SCO;
+            return fromGetVolumeControlStream ?
+                    AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
         }
 
         // usage to stream type mapping
@@ -753,7 +780,8 @@
             case USAGE_VOICE_COMMUNICATION:
                 return AudioSystem.STREAM_VOICE_CALL;
             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
-                return AudioSystem.STREAM_DTMF;
+                return fromGetVolumeControlStream ?
+                        AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_DTMF;
             case USAGE_ALARM:
                 return AudioSystem.STREAM_ALARM;
             case USAGE_NOTIFICATION_RINGTONE:
@@ -765,8 +793,15 @@
             case USAGE_NOTIFICATION_EVENT:
                 return AudioSystem.STREAM_NOTIFICATION;
             case USAGE_UNKNOWN:
+                return fromGetVolumeControlStream ?
+                        AudioManager.USE_DEFAULT_STREAM_TYPE : AudioSystem.STREAM_MUSIC;
             default:
-                return AudioSystem.STREAM_MUSIC;
+                if (fromGetVolumeControlStream) {
+                    throw new IllegalArgumentException("Unknown usage value " + aa.getUsage() +
+                            " in audio attributes");
+                } else {
+                    return AudioSystem.STREAM_MUSIC;
+                }
         }
     }
 
diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
index 85c451f..12a5f04 100644
--- a/media/java/android/media/midi/MidiReceiver.java
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -87,29 +87,38 @@
     }
 
     /**
-     * Called to send MIDI data to the receiver
+     * Called to send MIDI data to the receiver without a timestamp.
+     * Data will be processed by receiver in the order sent.
      * Data will get split into multiple calls to {@link #onSend} if count exceeds
-     * {@link #getMaxMessageSize}.
+     * {@link #getMaxMessageSize}.  Blocks until all the data is sent or an exception occurs.
+     * In the latter case, the amount of data sent prior to the exception is not provided to caller.
+     * The communication should be considered corrupt.  The sender should reestablish
+     * communication, reset all controllers and send all notes off.
      *
      * @param msg a byte array containing the MIDI data
      * @param offset the offset of the first byte of the data in the array to be sent
      * @param count the number of bytes of MIDI data in the array to be sent
-     * @throws IOException
+     * @throws IOException if the data could not be sent in entirety
      */
     public void send(byte[] msg, int offset, int count) throws IOException {
-        send(msg, offset, count, System.nanoTime());
+        // TODO add public static final TIMESTAMP_NONE = 0L
+        send(msg, offset, count, 0L);
     }
 
     /**
-     * Called to send MIDI data to the receiver to be handled at a specified time in the future
+     * Called to send MIDI data to the receiver with a specified timestamp.
+     * Data will be processed by receiver in order first by timestamp, then in the order sent.
      * Data will get split into multiple calls to {@link #onSend} if count exceeds
-     * {@link #getMaxMessageSize}.
+     * {@link #getMaxMessageSize}.  Blocks until all the data is sent or an exception occurs.
+     * In the latter case, the amount of data sent prior to the exception is not provided to caller.
+     * The communication should be considered corrupt.  The sender should reestablish
+     * communication, reset all controllers and send all notes off.
      *
      * @param msg a byte array containing the MIDI data
      * @param offset the offset of the first byte of the data in the array to be sent
      * @param count the number of bytes of MIDI data in the array to be sent
-     * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
-     * @throws IOException
+     * @param timestamp the timestamp of the message, based on {@link java.lang.System#nanoTime}
+     * @throws IOException if the data could not be sent in entirety
      */
     public void send(byte[] msg, int offset, int count, long timestamp)
             throws IOException {
diff --git a/packages/DocumentsUI/res/layout/fragment_pick.xml b/packages/DocumentsUI/res/layout/fragment_pick.xml
index 87dc4f8..40d4eb5 100644
--- a/packages/DocumentsUI/res/layout/fragment_pick.xml
+++ b/packages/DocumentsUI/res/layout/fragment_pick.xml
@@ -19,13 +19,13 @@
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:baselineAligned="false"
-    android:gravity="center_vertical"
+    android:gravity="end"
+    android:paddingEnd="8dp"
     android:minHeight="?android:attr/listPreferredItemHeightSmall">
     <Button
         android:id="@android:id/button2"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_weight="1"
         android:text="@android:string/cancel"
         android:visibility="gone"
         style="?android:attr/buttonBarNegativeButtonStyle" />
@@ -33,7 +33,5 @@
         android:id="@android:id/button1"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:textAllCaps="false"
         style="?android:attr/buttonBarPositiveButtonStyle" />
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 5281087..9794273 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -44,8 +44,6 @@
     <string name="menu_share">Share</string>
     <!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
     <string name="menu_delete">Delete</string>
-    <!-- Menu item title that selects the current directory [CHAR LIMIT=48] -->
-    <string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
     <!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
     <string name="menu_select_all">Select All</string>
     <!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
@@ -65,7 +63,9 @@
     <!-- Menu item that hides the sizes of displayed files [CHAR LIMIT=24] -->
     <string name="menu_file_size_hide">Hide file size</string>
 
-    <!-- Button label that copies files to the current directory [CHAR LIMIT=48] -->
+    <!-- Button label that select the current directory [CHAR LIMIT=24] -->
+    <string name="button_select">Select</string>
+    <!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
     <string name="button_copy">Copy</string>
 
     <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index cded717..8482438 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -571,9 +571,7 @@
             mState.action == ACTION_OPEN_COPY_DESTINATION) {
             final PickFragment pick = PickFragment.get(fm);
             if (pick != null) {
-                final CharSequence displayName = (mState.stack.size() <= 1) ? root.title
-                        : cwd.displayName;
-                pick.setPickTarget(mState.action, cwd, displayName);
+                pick.setPickTarget(mState.action, cwd);
             }
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index e899379..d9b8568 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -38,15 +38,19 @@
 public class PickFragment extends Fragment {
     public static final String TAG = "PickFragment";
 
+    private int mAction;
     private DocumentInfo mPickTarget;
-
     private View mContainer;
     private Button mPick;
     private Button mCancel;
 
     public static void show(FragmentManager fm) {
-        final PickFragment fragment = new PickFragment();
+        // Fragment can be restored by FragmentManager automatically.
+        if (get(fm) != null) {
+            return;
+        }
 
+        final PickFragment fragment = new PickFragment();
         final FragmentTransaction ft = fm.beginTransaction();
         ft.replace(R.id.container_save, fragment, TAG);
         ft.commitAllowingStateLoss();
@@ -67,8 +71,7 @@
         mCancel = (Button) mContainer.findViewById(android.R.id.button2);
         mCancel.setOnClickListener(mCancelListener);
 
-        setPickTarget(0, null, null);
-
+        updateView();
         return mContainer;
     }
 
@@ -92,32 +95,38 @@
     /**
      * @param action Which action defined in BaseActivity.State is the picker shown for.
      */
-    public void setPickTarget(int action,
-                              DocumentInfo pickTarget,
-                              CharSequence displayName) {
-        if (mContainer != null) {
-            if (pickTarget != null) {
-                final Locale locale = getResources().getConfiguration().locale;
-                switch (action) {
-                    case BaseActivity.State.ACTION_OPEN_TREE:
-                        final String raw = getString(R.string.menu_select).toUpperCase(locale);
-                        mPick.setText(TextUtils.expandTemplate(raw, displayName));
-                        mCancel.setVisibility(View.GONE);
-                        break;
-                    case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
-                        mPick.setText(getString(R.string.button_copy).toUpperCase(locale));
-                        mCancel.setVisibility(View.VISIBLE);
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Illegal action for PickFragment.");
-                }
-            }
-            if (pickTarget != null && pickTarget.isCreateSupported()) {
-                mContainer.setVisibility(View.VISIBLE);
-            } else {
-                mContainer.setVisibility(View.GONE);
-            }
-        }
+    public void setPickTarget(int action, DocumentInfo pickTarget) {
+        mAction = action;
         mPickTarget = pickTarget;
+        if (mContainer != null) {
+            updateView();
+        }
+    }
+
+    /**
+     * Applies the state of fragment to the view components.
+     */
+    private void updateView() {
+        switch (mAction) {
+            case BaseActivity.State.ACTION_OPEN_TREE:
+                mPick.setText(R.string.button_select);
+                mCancel.setVisibility(View.GONE);
+                break;
+            case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+                mPick.setText(R.string.button_copy);
+                mCancel.setVisibility(View.VISIBLE);
+                break;
+            default:
+                mContainer.setVisibility(View.GONE);
+                return;
+        }
+
+        if (mPickTarget != null && (
+                mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+                mPickTarget.isCreateSupported())) {
+            mContainer.setVisibility(View.VISIBLE);
+        } else {
+            mContainer.setVisibility(View.GONE);
+        }
     }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 3fcc3c3..f18c451 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -35,6 +35,8 @@
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
+import com.android.internal.widget.TextViewInputDisabler;
+
 import java.util.List;
 /**
  * Displays an alphanumeric (latin-1) key entry for the user to enter
@@ -49,6 +51,8 @@
 
     InputMethodManager mImm;
     private TextView mPasswordEntry;
+    private TextViewInputDisabler mPasswordEntryDisabler;
+
     private Interpolator mLinearOutSlowInInterpolator;
     private Interpolator mFastOutLinearInInterpolator;
 
@@ -70,7 +74,7 @@
 
     protected void resetState() {
         mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false);
-        mPasswordEntry.setEnabled(true);
+        setPasswordEntryEnabled(true);
     }
 
     @Override
@@ -123,6 +127,7 @@
                 Context.INPUT_METHOD_SERVICE);
 
         mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
+        mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry);
         mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
         mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_VARIATION_PASSWORD);
@@ -185,7 +190,7 @@
 
     @Override
     protected void setPasswordEntryEnabled(boolean enabled) {
-        mPasswordEntry.setEnabled(enabled);
+        mPasswordEntryDisabler.setInputEnabled(enabled);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 5d6b2f1..d3e7104 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -51,11 +51,13 @@
     private final Collection<BluetoothCallback> mCallbacks =
             new ArrayList<BluetoothCallback>();
 
+    private android.os.Handler mReceiverHandler;
+
     interface Handler {
         void onReceive(Context context, Intent intent, BluetoothDevice device);
     }
 
-    void addHandler(String action, Handler handler) {
+    private void addHandler(String action, Handler handler) {
         mHandlerMap.put(action, handler);
         mAdapterIntentFilter.addAction(action);
     }
@@ -103,11 +105,18 @@
         // Dock event broadcasts
         addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
 
-        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
+        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
     }
 
     void registerProfileIntentReceiver() {
-        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
+        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
+    }
+
+    public void setReceiverHandler(android.os.Handler handler) {
+        mContext.unregisterReceiver(mBroadcastReceiver);
+        mReceiverHandler = handler;
+        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
+        registerProfileIntentReceiver();
     }
 
     /** Register to start receiving callbacks for Bluetooth events. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 9e2207e..2dc521e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -105,6 +105,13 @@
         return mPanelShowing;
     }
 
+    public void abortCurrentGesture() {
+        if (mStarted) {
+            mStarted = false;
+            mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
+        }
+    }
+
     public void setSourceView(View view) {
         mSourceView = view;
         if (mSourceView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 7077a17..1dec227 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -245,6 +245,11 @@
         return intercept;
     }
 
+    public void abortCurrentGesture() {
+        mDelegateHelper.abortCurrentGesture();
+        getHomeButton().abortCurrentGesture();
+    }
+
     private H mHandler = new H();
 
     public View getCurrentView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9ef9211..c10be7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -117,6 +117,7 @@
      * intercepted yet.
      */
     private boolean mIntercepting;
+    private boolean mPanelExpanded;
     private boolean mQsExpanded;
     private boolean mQsExpandedWhenExpandingStarted;
     private boolean mQsFullyExpanded;
@@ -1496,13 +1497,22 @@
         updateHeader();
         updateUnlockIcon();
         updateNotificationTranslucency();
-        mHeadsUpManager.setIsExpanded(!isFullyCollapsed());
+        updatePanelExpanded();
         mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
         if (DEBUG) {
             invalidate();
         }
     }
 
+    private void updatePanelExpanded() {
+        boolean isExpanded = !isFullyCollapsed();
+        if (mPanelExpanded != isExpanded) {
+            mHeadsUpManager.setIsExpanded(isExpanded);
+            mStatusBar.setPanelExpanded(isExpanded);
+            mPanelExpanded = isExpanded;
+        }
+    }
+
     /**
      * @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
      *         collapsing QS / the panel when QS was scrolled
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2a9df19..9fe591e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1013,7 +1013,7 @@
             invokeAssistGesture(true /* vibrate */);
             awakenDreams();
             if (mNavigationBarView != null) {
-                mNavigationBarView.getHomeButton().abortCurrentGesture();
+                mNavigationBarView.abortCurrentGesture();
             }
         }
     };
@@ -1967,6 +1967,10 @@
         return !mUnlockMethodCache.isCurrentlyInsecure();
     }
 
+    public void setPanelExpanded(boolean isExpanded) {
+        mStatusBarWindowManager.setPanelExpanded(isExpanded);
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2027,7 +2031,7 @@
 
         // Expand the window to encompass the full screen in anticipation of the drag.
         // This is only possible to do atomically because the status bar is at the top of the screen!
-        mStatusBarWindowManager.setStatusBarExpanded(true);
+        mStatusBarWindowManager.setPanelVisible(true);
         mStatusBarView.setFocusable(false);
 
         visibilityChanged(true);
@@ -2156,7 +2160,7 @@
         visibilityChanged(false);
 
         // Shrink the window to the size of the status bar only
-        mStatusBarWindowManager.setStatusBarExpanded(false);
+        mStatusBarWindowManager.setPanelVisible(false);
         mStatusBarWindowManager.setForceStatusBarVisible(false);
         mStatusBarView.setFocusable(true);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 422d868..4f1c652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -114,12 +114,12 @@
     }
 
     private void applyFocusableFlag(State state) {
+        boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
         if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
-                && state.bouncerShowing
-                || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) {
+                && state.bouncerShowing || BaseStatusBar.ENABLE_REMOTE_INPUT && panelFocusable) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
+        } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else {
@@ -130,7 +130,7 @@
 
     private void applyHeight(State state) {
         boolean expanded = !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
-                || state.statusBarExpanded || state.keyguardFadingAway || state.bouncerShowing
+                || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
                 || state.headsUpShowing);
         if (expanded) {
             mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -213,9 +213,9 @@
         apply(mCurrentState);
     }
 
-    public void setStatusBarExpanded(boolean expanded) {
-        mCurrentState.statusBarExpanded = expanded;
-        mCurrentState.statusBarFocusable = expanded;
+    public void setPanelVisible(boolean visible) {
+        mCurrentState.panelVisible = visible;
+        mCurrentState.statusBarFocusable = visible;
         apply(mCurrentState);
     }
 
@@ -267,11 +267,17 @@
         apply(mCurrentState);
     }
 
+    public void setPanelExpanded(boolean isExpanded) {
+        mCurrentState.panelExpanded = isExpanded;
+        apply(mCurrentState);
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
         boolean keyguardNeedsInput;
-        boolean statusBarExpanded;
+        boolean panelVisible;
+        boolean panelExpanded;
         boolean statusBarFocusable;
         boolean bouncerShowing;
         boolean keyguardFadingAway;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 5893cb2..0eb7197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -45,7 +45,7 @@
     private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid";
 
     private static final int[] ICONS = {
-        R.drawable.ic_qs_wifi_0,
+        R.drawable.ic_qs_wifi_full_0,
         R.drawable.ic_qs_wifi_full_1,
         R.drawable.ic_qs_wifi_full_2,
         R.drawable.ic_qs_wifi_full_3,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 8d4f302..114427c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -18,7 +18,9 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
+import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.util.Log;
 
 import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -42,9 +44,12 @@
     private boolean mConnecting;
     private CachedBluetoothDevice mLastDevice;
 
+    private final H mHandler = new H();
+
     public BluetoothControllerImpl(Context context, Looper bgLooper) {
         mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, null);
         if (mLocalBluetoothManager != null) {
+            mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
             mLocalBluetoothManager.getEventManager().registerCallback(this);
             onBluetoothStateChanged(
                     mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
@@ -71,7 +76,7 @@
 
     public void addStateChangedCallback(Callback cb) {
         mCallbacks.add(cb);
-        fireStateChange(cb);
+        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
     }
 
     @Override
@@ -132,22 +137,6 @@
                 : null;
     }
 
-    private void firePairedDevicesChanged() {
-        for (Callback cb : mCallbacks) {
-            cb.onBluetoothDevicesChanged();
-        }
-    }
-
-    private void fireStateChange() {
-        for (Callback cb : mCallbacks) {
-            fireStateChange(cb);
-        }
-    }
-
-    private void fireStateChange(Callback cb) {
-        cb.onBluetoothStateChange(mEnabled, mConnecting);
-    }
-
     private void updateConnected() {
         if (mLastDevice != null && mLastDevice.isConnected()) {
             // Our current device is still valid.
@@ -163,7 +152,7 @@
     @Override
     public void onBluetoothStateChanged(int bluetoothState) {
         mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
-        fireStateChange();
+        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
     }
 
     @Override
@@ -175,25 +164,25 @@
     public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
         cachedDevice.registerCallback(this);
         updateConnected();
-        firePairedDevicesChanged();
+        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
     }
 
     @Override
     public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
         updateConnected();
-        firePairedDevicesChanged();
+        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
     }
 
     @Override
     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
         updateConnected();
-        firePairedDevicesChanged();
+        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
     }
 
     @Override
     public void onDeviceAttributesChanged() {
         updateConnected();
-        firePairedDevicesChanged();
+        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
     }
 
     @Override
@@ -201,6 +190,39 @@
         mConnecting = state == BluetoothAdapter.STATE_CONNECTING;
         mLastDevice = cachedDevice;
         updateConnected();
-        fireStateChange();
+        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+    }
+
+    private final class H extends Handler {
+        private static final int MSG_PAIRED_DEVICES_CHANGED = 1;
+        private static final int MSG_STATE_CHANGED = 2;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PAIRED_DEVICES_CHANGED:
+                    firePairedDevicesChanged();
+                    break;
+                case MSG_STATE_CHANGED:
+                    fireStateChange();
+                    break;
+            }
+        }
+
+        private void firePairedDevicesChanged() {
+            for (BluetoothController.Callback cb : mCallbacks) {
+                cb.onBluetoothDevicesChanged();
+            }
+        }
+
+        private void fireStateChange() {
+            for (BluetoothController.Callback cb : mCallbacks) {
+                fireStateChange(cb);
+            }
+        }
+
+        private void fireStateChange(BluetoothController.Callback cb) {
+            cb.onBluetoothStateChange(mEnabled, mConnecting);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 23813d1..ad21555 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -148,6 +148,11 @@
                 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
 
         // Kick current state into place
+        final List<DiskInfo> disks = mStorageManager.getDisks();
+        for (DiskInfo disk : disks) {
+            onDiskScannedInternal(disk, disk.volumeCount);
+        }
+
         final List<VolumeInfo> vols = mStorageManager.getVolumes();
         for (VolumeInfo vol : vols) {
             onVolumeStateChangedInternal(vol);
@@ -194,7 +199,7 @@
     }
 
     private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
-        if (volumeCount == 0) {
+        if (volumeCount == 0 && disk.size > 0) {
             // No supported volumes found, give user option to format
             final CharSequence title = mContext.getString(
                     R.string.ext_media_unmountable_notification_title, disk.getDescription());
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 6e0ca3c..1c6462e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -724,7 +724,7 @@
                 }
                 row.slider.setProgress(newProgress);
             }
-            if (mAutomute) {
+            if (mAutomute && mShowing) {
                 if (vlevel == 0 && !row.ss.muted && row.stream == AudioManager.STREAM_MUSIC) {
                     mController.setStreamMute(row.stream, true);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 3a8081f..c6d9e46 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -180,7 +180,7 @@
         pw.print("  mEnabled: "); pw.println(mEnabled);
         pw.print("  mDestroyed: "); pw.println(mDestroyed);
         pw.print("  mVolumePolicy: "); pw.println(mVolumePolicy);
-        pw.print("  mEnabled: "); pw.println(mEnabled);
+        pw.print("  mState: "); pw.println(mState.toString(4));
         pw.print("  mShowDndTile: "); pw.println(mShowDndTile);
         pw.print("  mHasVibrator: "); pw.println(mHasVibrator);
         pw.print("  mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
@@ -960,25 +960,45 @@
 
         @Override
         public String toString() {
+            return toString(0);
+        }
+
+        public String toString(int indent) {
             final StringBuilder sb = new StringBuilder("{");
+            if (indent > 0) sep(sb, indent);
             for (int i = 0; i < states.size(); i++) {
-                if (i > 0) sb.append(',');
+                if (i > 0) {
+                    sep(sb, indent);
+                }
                 final int stream = states.keyAt(i);
                 final StreamState ss = states.valueAt(i);
                 sb.append(AudioSystem.streamToString(stream)).append(":").append(ss.level)
-                        .append("[").append(ss.levelMin).append("..").append(ss.levelMax);
+                        .append('[').append(ss.levelMin).append("..").append(ss.levelMax)
+                        .append(']');
                 if (ss.muted) sb.append(" [MUTED]");
             }
-            sb.append(",ringerModeExternal:").append(ringerModeExternal);
-            sb.append(",ringerModeInternal:").append(ringerModeInternal);
-            sb.append(",zenMode:").append(zenMode);
-            sb.append(",effectsSuppressor:").append(effectsSuppressor);
-            sb.append(",effectsSuppressorName:").append(effectsSuppressorName);
-            sb.append(",zenModeConfig:").append(zenModeConfig);
-            sb.append(",activeStream:").append(activeStream);
+            sep(sb, indent); sb.append("ringerModeExternal:").append(ringerModeExternal);
+            sep(sb, indent); sb.append("ringerModeInternal:").append(ringerModeInternal);
+            sep(sb, indent); sb.append("zenMode:").append(zenMode);
+            sep(sb, indent); sb.append("effectsSuppressor:").append(effectsSuppressor);
+            sep(sb, indent); sb.append("effectsSuppressorName:").append(effectsSuppressorName);
+            sep(sb, indent); sb.append("zenModeConfig:").append(zenModeConfig);
+            sep(sb, indent); sb.append("activeStream:").append(activeStream);
+            if (indent > 0) sep(sb, indent);
             return sb.append('}').toString();
         }
 
+        private static void sep(StringBuilder sb, int indent) {
+            if (indent > 0) {
+                sb.append('\n');
+                for (int i = 0; i < indent; i++) {
+                    sb.append(' ');
+                }
+            } else {
+                sb.append(',');
+            }
+        }
+
         public Condition getManualExitCondition() {
             return zenModeConfig != null && zenModeConfig.manualRule != null
                     ? zenModeConfig.manualRule.condition : null;
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index ea8b2ec..48e0582 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.IConnectivityManager;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.text.Html;
 import android.text.Html.ImageGetter;
 import android.util.Log;
@@ -50,7 +51,7 @@
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
-            if (mService.prepareVpn(mPackage, null)) {
+            if (mService.prepareVpn(mPackage, null, UserHandle.myUserId())) {
                 setResult(RESULT_OK);
                 finish();
                 return;
@@ -94,10 +95,10 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         try {
-            if (mService.prepareVpn(null, mPackage)) {
+            if (mService.prepareVpn(null, mPackage, UserHandle.myUserId())) {
                 // Authorize this app to initiate VPN connections in the future without user
                 // intervention.
-                mService.setVpnPackageAuthorization(true);
+                mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), true);
                 setResult(RESULT_OK);
             }
         } catch (Exception e) {
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index cc8500a..76b2346 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
@@ -63,7 +64,7 @@
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
-            mConfig = mService.getVpnConfig();
+            mConfig = mService.getVpnConfig(UserHandle.myUserId());
 
             // mConfig can be null if we are a restricted user, in that case don't show this dialog
             if (mConfig == null) {
@@ -120,10 +121,11 @@
             if (which == DialogInterface.BUTTON_POSITIVE) {
                 mConfig.configureIntent.send();
             } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+                final int myUserId = UserHandle.myUserId();
                 if (mConfig.legacy) {
-                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
                 } else {
-                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
                 }
             }
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 7d427d6..79c66b9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -408,11 +408,19 @@
             }
         }
         if (repCbs != null) {
-            for (int i=0; i<repCbs.size(); i++) {
-                try {
-                    repCbs.get(i).mCallback.opChanged(code, packageName);
-                } catch (RemoteException e) {
+            // There are components watching for mode changes such as window manager
+            // and location manager which are in our process. The callbacks in these
+            // components may require permissions our remote caller does not have.
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (int i = 0; i < repCbs.size(); i++) {
+                    try {
+                        repCbs.get(i).mCallback.opChanged(code, packageName);
+                    } catch (RemoteException e) {
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 02bffc4..7ac2655 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1071,23 +1071,6 @@
         }
     }
 
-    private NetworkCapabilities getNetworkCapabilitiesAndValidation(NetworkAgentInfo nai) {
-        if (nai != null) {
-            synchronized (nai) {
-                if (nai.created) {
-                    NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
-                    if (nai.lastValidated) {
-                        nc.addCapability(NET_CAPABILITY_VALIDATED);
-                    } else {
-                        nc.removeCapability(NET_CAPABILITY_VALIDATED);
-                    }
-                    return nc;
-                }
-            }
-        }
-        return null;
-    }
-
     @Override
     public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
         // The basic principle is: if an app's traffic could possibly go over a
@@ -1109,7 +1092,7 @@
         HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
 
         NetworkAgentInfo nai = getDefaultNetwork();
-        NetworkCapabilities nc = getNetworkCapabilitiesAndValidation(getDefaultNetwork());
+        NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
         if (nc != null) {
             result.put(nai.network, nc);
         }
@@ -1122,9 +1105,9 @@
                     if (networks != null) {
                         for (Network network : networks) {
                             nai = getNetworkAgentInfoForNetwork(network);
-                            nc = getNetworkCapabilitiesAndValidation(nai);
+                            nc = getNetworkCapabilitiesInternal(nai);
                             if (nc != null) {
-                                result.put(nai.network, nc);
+                                result.put(network, nc);
                             }
                         }
                     }
@@ -1184,25 +1167,24 @@
         return null;
     }
 
-    @Override
-    public NetworkCapabilities getNetworkCapabilities(Network network) {
-        enforceAccessPermission();
-        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+    private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai != null) {
             synchronized (nai) {
-                NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
-                if (nai.lastValidated) {
-                    nc.addCapability(NET_CAPABILITY_VALIDATED);
-                } else {
-                    nc.removeCapability(NET_CAPABILITY_VALIDATED);
+                if (nai.networkCapabilities != null) {
+                    return new NetworkCapabilities(nai.networkCapabilities);
                 }
-                return nc;
             }
         }
         return null;
     }
 
     @Override
+    public NetworkCapabilities getNetworkCapabilities(Network network) {
+        enforceAccessPermission();
+        return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+    }
+
+    @Override
     public NetworkState[] getAllNetworkState() {
         // Require internal since we're handing out IMSI details
         enforceConnectivityInternalPermission();
@@ -1410,6 +1392,22 @@
         }
     };
 
+    /**
+     * Require that the caller is either in the same user or has appropriate permission to interact
+     * across users.
+     *
+     * @param userId Target user for whatever operation the current IPC is supposed to perform.
+     */
+    private void enforceCrossUserPermission(int userId) {
+        if (userId == UserHandle.getCallingUserId()) {
+            // Not a cross-user call.
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                "ConnectivityService");
+    }
+
     private void enforceInternetPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INTERNET,
@@ -1950,11 +1948,14 @@
                 }
                 case NetworkMonitor.EVENT_NETWORK_TESTED: {
                     NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
-                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
-                        boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_TESTED")) {
+                        final boolean valid =
+                                (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                        final boolean validationChanged = (valid != nai.lastValidated);
                         nai.lastValidated = valid;
                         if (valid) {
                             if (DBG) log("Validated " + nai.name());
+                            nai.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
                             if (!nai.everValidated) {
                                 nai.everValidated = true;
                                 rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
@@ -1962,6 +1963,8 @@
                                 // If score has changed, rebroadcast to NetworkFactories. b/17726566
                                 sendUpdatedScoreToFactories(nai);
                             }
+                        } else {
+                            nai.networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
                         }
                         updateInetCondition(nai);
                         // Let the NetworkAgent know the state of its network
@@ -1970,8 +1973,9 @@
                                 (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                                 0, null);
 
-                        // TODO: trigger a NetworkCapabilities update so that the dialog can know
-                        // that the network is now validated and close itself.
+                        if (validationChanged) {
+                            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+                        }
                     }
                     break;
                 }
@@ -2684,7 +2688,7 @@
                 actionToken);
     }
 
-    public ProxyInfo getDefaultProxy() {
+    private ProxyInfo getDefaultProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
@@ -2696,6 +2700,22 @@
         }
     }
 
+    public ProxyInfo getProxyForNetwork(Network network) {
+        if (network == null) return getDefaultProxy();
+        final ProxyInfo globalProxy = getGlobalProxy();
+        if (globalProxy != null) return globalProxy;
+        if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null;
+        // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
+        // caller may not have.
+        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai == null) return null;
+        synchronized (nai) {
+            final ProxyInfo proxyInfo = nai.linkProperties.getHttpProxy();
+            if (proxyInfo == null) return null;
+            return new ProxyInfo(proxyInfo);
+        }
+    }
+
     // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
     // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
     // proxy is null then there is no proxy in place).
@@ -2945,29 +2965,48 @@
 
     /**
      * Prepare for a VPN application.
-     * Permissions are checked in Vpn class.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param oldPackage Package name of the application which currently controls VPN, which will
+     *                   be replaced. If there is no such application, this should should either be
+     *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
+     * @param newPackage Package name of the application which should gain control of VPN, or
+     *                   {@code null} to disable.
+     * @param userId User for whom to prepare the new VPN.
+     *
      * @hide
      */
     @Override
-    public boolean prepareVpn(String oldPackage, String newPackage) {
+    public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+            int userId) {
+        enforceCrossUserPermission(userId);
         throwIfLockdownEnabled();
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+
         synchronized(mVpns) {
-            return mVpns.get(user).prepare(oldPackage, newPackage);
+            return mVpns.get(userId).prepare(oldPackage, newPackage);
         }
     }
 
     /**
-     * Set whether the current VPN package has the ability to launch VPNs without
-     * user intervention. This method is used by system-privileged apps.
-     * Permissions are checked in Vpn class.
+     * Set whether the VPN package has the ability to launch VPNs without user intervention.
+     * This method is used by system-privileged apps.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param packageName The package for which authorization state should change.
+     * @param userId User for whom {@code packageName} is installed.
+     * @param authorized {@code true} if this app should be able to start a VPN connection without
+     *                   explicit user approval, {@code false} if not.
+     *
      * @hide
      */
     @Override
-    public void setVpnPackageAuthorization(boolean authorized) {
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+    public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
+        enforceCrossUserPermission(userId);
+
         synchronized(mVpns) {
-            mVpns.get(user).setPackageAuthorization(authorized);
+            mVpns.get(userId).setPackageAuthorization(packageName, authorized);
         }
     }
 
@@ -3069,16 +3108,16 @@
     }
 
     /**
-     * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
-     * not available in ConnectivityManager.
+     * Returns the information of the ongoing VPN for {@code userId}. This method is used by
+     * VpnDialogs and not available in ConnectivityManager.
      * Permissions are checked in Vpn class.
      * @hide
      */
     @Override
-    public VpnConfig getVpnConfig() {
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+    public VpnConfig getVpnConfig(int userId) {
+        enforceCrossUserPermission(userId);
         synchronized(mVpns) {
-            return mVpns.get(user).getVpnConfig();
+            return mVpns.get(userId).getVpnConfig();
         }
     }
 
@@ -3534,8 +3573,7 @@
     }
 
     private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities) {
-        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
-                == false) {
+        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
             enforceConnectivityInternalPermission();
         } else {
             enforceChangePermission();
@@ -3562,8 +3600,7 @@
 
     private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
         // if UID is restricted, don't allow them to bring up metered APNs
-        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
-                == false) {
+        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
             final int uidRules;
             final int uid = Binder.getCallingUid();
             synchronized(mRulesLock) {
@@ -3934,6 +3971,11 @@
             synchronized (networkAgent) {
                 networkAgent.networkCapabilities = networkCapabilities;
             }
+            if (networkAgent.lastValidated) {
+                networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+                // There's no need to remove the capability if we think the network is unvalidated,
+                // because NetworkAgents don't set the validated capability.
+            }
             rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore());
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
@@ -4560,6 +4602,8 @@
     @Override
     public void factoryReset() {
         enforceConnectivityInternalPermission();
+        final int userId = UserHandle.getCallingUserId();
+
         // Turn airplane mode off
         setAirplaneMode(false);
 
@@ -4569,16 +4613,16 @@
         }
 
         // Turn VPN off
-        VpnConfig vpnConfig = getVpnConfig();
+        VpnConfig vpnConfig = getVpnConfig(userId);
         if (vpnConfig != null) {
             if (vpnConfig.legacy) {
-                prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
             } else {
-                // Prevent this app from initiating VPN connections in the future without
-                // user intervention.
-                setVpnPackageAuthorization(false);
+                // Prevent this app (packagename = vpnConfig.user) from initiating VPN connections
+                // in the future without user intervention.
+                setVpnPackageAuthorization(vpnConfig.user, userId, false);
 
-                prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN);
+                prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN, userId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index e00cf5b..d48953d 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -973,6 +973,7 @@
             }
         }
 
+        disk.volumeCount = volumeCount;
         mCallbacks.notifyDiskScanned(disk, volumeCount);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 925fae0a..ec2bd67 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -71,6 +71,7 @@
     static final boolean DEBUG_TASKS = DEBUG_ALL || false;
     static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
     static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+    static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
     static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
     static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
     static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
@@ -104,6 +105,8 @@
     static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
     static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : "";
     static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
+    static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME)
+            ? "_UidObservers" : "";
     static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
     static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
     static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2d74618..6842304 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -129,6 +129,7 @@
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
 import android.app.IStopUserCallback;
+import android.app.IUidObserver;
 import android.app.IUiAutomationConnection;
 import android.app.IUserSwitchObserver;
 import android.app.Instrumentation;
@@ -253,7 +254,6 @@
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
-    private static final String USER_DATA_DIR = "/data/user/";
     // File that stores last updated system version and called preboot receivers
     static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
 
@@ -278,6 +278,7 @@
     private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
     private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
@@ -655,9 +656,14 @@
     long mPreviousProcessVisibleTime;
 
     /**
+     * Track all uids that have actively running processes.
+     */
+    final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
+
+    /**
      * Which uses have been started, so are allowed to run code.
      */
-    final SparseArray<UserStartedState> mStartedUsers = new SparseArray<UserStartedState>();
+    final SparseArray<UserStartedState> mStartedUsers = new SparseArray<>();
 
     /**
      * LRU list of history of current users.  Most recently current is at the end.
@@ -1023,6 +1029,11 @@
     private IVoiceInteractionSession mRunningVoice;
 
     /**
+     * For some direct access we need to power manager.
+     */
+    PowerManagerInternal mLocalPowerManager;
+
+    /**
      * We want to hold a wake lock while running a voice interaction session, since
      * this may happen with the screen off and we need to keep the CPU running to
      * be able to continue to interact with the user.
@@ -1174,7 +1185,7 @@
 
     final long[] mTmpLong = new long[1];
 
-    static class ProcessChangeItem {
+    static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
         static final int CHANGE_PROCESS_STATE = 1<<1;
         int changes;
@@ -1184,14 +1195,17 @@
         boolean foregroundActivities;
     }
 
-    final RemoteCallbackList<IProcessObserver> mProcessObservers
-            = new RemoteCallbackList<IProcessObserver>();
+    final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
     ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
 
-    final ArrayList<ProcessChangeItem> mPendingProcessChanges
-            = new ArrayList<ProcessChangeItem>();
-    final ArrayList<ProcessChangeItem> mAvailProcessChanges
-            = new ArrayList<ProcessChangeItem>();
+    final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>();
+    final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>();
+
+    final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>();
+    UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5];
+
+    final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>();
+    final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>();
 
     /**
      * Runtime CPU use collection thread.  This object's lock is used to
@@ -1316,6 +1330,7 @@
     static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
     static final int DELETE_DUMPHEAP_MSG = 52;
     static final int FOREGROUND_PROFILE_CHANGED_MSG = 53;
+    static final int DISPATCH_UIDS_CHANGED = 54;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1538,6 +1553,19 @@
                 d.dismiss();
                 break;
             }
+            case DISPATCH_PROCESSES_CHANGED: {
+                dispatchProcessesChanged();
+                break;
+            }
+            case DISPATCH_PROCESS_DIED: {
+                final int pid = msg.arg1;
+                final int uid = msg.arg2;
+                dispatchProcessDied(pid, uid);
+                break;
+            }
+            case DISPATCH_UIDS_CHANGED: {
+                dispatchUidsChanged();
+            } break;
             }
         }
     }
@@ -1723,16 +1751,6 @@
                     sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 }
             } break;
-            case DISPATCH_PROCESSES_CHANGED: {
-                dispatchProcessesChanged();
-                break;
-            }
-            case DISPATCH_PROCESS_DIED: {
-                final int pid = msg.arg1;
-                final int uid = msg.arg2;
-                dispatchProcessDied(pid, uid);
-                break;
-            }
             case REPORT_MEM_USAGE_MSG: {
                 final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
                 Thread thread = new Thread() {
@@ -2091,7 +2109,6 @@
                 app.pid = MY_PID;
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
                 app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
-                mProcessNames.put(app.processName, app.uid, app);
                 synchronized (mPidsSelfLocked) {
                     mPidsSelfLocked.put(app.pid, app);
                 }
@@ -2343,6 +2360,7 @@
     public void initPowerManagement() {
         mStackSupervisor.initPowerManagement();
         mBatteryStatsService.initPowerManagement();
+        mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
         PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
         mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
         mVoiceWakeLock.setReferenceCounted(false);
@@ -3073,10 +3091,6 @@
                 return null;
             }
             app.crashHandler = crashHandler;
-            mProcessNames.put(processName, app.uid, app);
-            if (isolated) {
-                mIsolatedProcesses.put(app.uid, app);
-            }
             checkTime(startTime, "startProcess: done creating new process record");
         } else {
             // If this is a new package in the process, add the package to the list
@@ -3562,7 +3576,6 @@
                 mActiveProcessChanges = new ProcessChangeItem[N];
             }
             mPendingProcessChanges.toArray(mActiveProcessChanges);
-            mAvailProcessChanges.addAll(mPendingProcessChanges);
             mPendingProcessChanges.clear();
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "*** Delivering " + N + " process changes");
@@ -3595,6 +3608,12 @@
             }
         }
         mProcessObservers.finishBroadcast();
+
+        synchronized (this) {
+            for (int j=0; j<N; j++) {
+                mAvailProcessChanges.add(mActiveProcessChanges[j]);
+            }
+        }
     }
 
     private void dispatchProcessDied(int pid, int uid) {
@@ -3612,6 +3631,67 @@
         mProcessObservers.finishBroadcast();
     }
 
+    private void dispatchUidsChanged() {
+        int N;
+        synchronized (this) {
+            N = mPendingUidChanges.size();
+            if (mActiveUidChanges.length < N) {
+                mActiveUidChanges = new UidRecord.ChangeItem[N];
+            }
+            for (int i=0; i<N; i++) {
+                final UidRecord.ChangeItem change = mPendingUidChanges.get(i);
+                mActiveUidChanges[i] = change;
+                change.uidRecord.pendingChange = null;
+                change.uidRecord = null;
+            }
+            mPendingUidChanges.clear();
+            if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                    "*** Delivering " + N + " uid changes");
+        }
+
+        if (mLocalPowerManager != null) {
+            for (int j=0; j<N; j++) {
+                UidRecord.ChangeItem item = mActiveUidChanges[j];
+                if (item.gone) {
+                    mLocalPowerManager.uidGone(item.uid);
+                } else {
+                    mLocalPowerManager.updateUidProcState(item.uid, item.processState);
+                }
+            }
+        }
+
+        int i = mUidObservers.beginBroadcast();
+        while (i > 0) {
+            i--;
+            final IUidObserver observer = mUidObservers.getBroadcastItem(i);
+            if (observer != null) {
+                try {
+                    for (int j=0; j<N; j++) {
+                        UidRecord.ChangeItem item = mActiveUidChanges[j];
+                        if (item.gone) {
+                            if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                                    "UID gone uid=" + item.uid);
+                            observer.onUidGone(item.uid);
+                        } else {
+                            if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                                    "UID CHANGED uid=" + item.uid
+                                    + ": " + item.processState);
+                            observer.onUidStateChanged(item.uid, item.processState);
+                        }
+                    }
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        mUidObservers.finishBroadcast();
+
+        synchronized (this) {
+            for (int j=0; j<N; j++) {
+                mAvailUidChanges.add(mActiveUidChanges[j]);
+            }
+        }
+    }
+
     @Override
     public final int startActivity(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
@@ -5623,6 +5703,47 @@
         return didSomething;
     }
 
+    private final ProcessRecord removeProcessNameLocked(final String name, final int uid) {
+        ProcessRecord old = mProcessNames.remove(name, uid);
+        if (old != null) {
+            old.uidRecord.numProcs--;
+            if (old.uidRecord.numProcs == 0) {
+                // No more processes using this uid, tell clients it is gone.
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                        "No more processes in " + old.uidRecord);
+                enqueueUidChangeLocked(old.uidRecord, true);
+                mActiveUids.remove(uid);
+            }
+            old.uidRecord = null;
+        }
+        mIsolatedProcesses.remove(uid);
+        return old;
+    }
+
+    private final void addProcessNameLocked(ProcessRecord proc) {
+        // We shouldn't already have a process under this name, but just in case we
+        // need to clean up whatever may be there now.
+        ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
+        if (old != null) {
+            Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc);
+        }
+        UidRecord uidRec = mActiveUids.get(proc.uid);
+        if (uidRec == null) {
+            uidRec = new UidRecord(proc.uid);
+            // This is the first appearance of the uid, report it now!
+            if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                    "Creating new process uid: " + uidRec);
+            mActiveUids.put(proc.uid, uidRec);
+            enqueueUidChangeLocked(uidRec, false);
+        }
+        proc.uidRecord = uidRec;
+        uidRec.numProcs++;
+        mProcessNames.put(proc.processName, proc.uid, proc);
+        if (proc.isolated) {
+            mIsolatedProcesses.put(proc.uid, proc);
+        }
+    }
+
     private final boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
@@ -5630,8 +5751,7 @@
         if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
             "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
 
-        mProcessNames.remove(name, uid);
-        mIsolatedProcesses.remove(app.uid);
+        removeProcessNameLocked(name, uid);
         if (mHeavyWeightProcess == app) {
             mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                     mHeavyWeightProcess.userId, 0));
@@ -5684,8 +5804,7 @@
             Slog.w(TAG, "Process " + app + " failed to attach");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
                     pid, app.uid, app.processName);
-            mProcessNames.remove(app.processName, app.uid);
-            mIsolatedProcesses.remove(app.uid);
+            removeProcessNameLocked(app.processName, app.uid);
             if (mHeavyWeightProcess == app) {
                 mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                         mHeavyWeightProcess.userId, 0));
@@ -9874,7 +9993,6 @@
     final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
             boolean isolated, int isolatedUid) {
         String proc = customProcess != null ? customProcess : info.processName;
-        BatteryStatsImpl.Uid.Proc ps = null;
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         final int userId = UserHandle.getUserId(info.uid);
         int uid = info.uid;
@@ -9909,6 +10027,7 @@
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
             r.persistent = true;
         }
+        addProcessNameLocked(r);
         return r;
     }
 
@@ -9923,10 +10042,6 @@
 
         if (app == null) {
             app = newProcessRecordLocked(info, null, isolated, 0);
-            mProcessNames.put(info.processName, app.uid, app);
-            if (isolated) {
-                mIsolatedProcesses.put(app.uid, app);
-            }
             updateLruProcessLocked(app, false, null);
             updateOomAdjLocked();
         }
@@ -10602,6 +10717,21 @@
         }
     }
 
+    public void registerUidObserver(IUidObserver observer) {
+        enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "registerUidObserver()");
+        synchronized (this) {
+            mUidObservers.register(observer);
+        }
+    }
+
+    @Override
+    public void unregisterUidObserver(IUidObserver observer) {
+        synchronized (this) {
+            mUidObservers.unregister(observer);
+        }
+    }
+
     @Override
     public boolean convertFromTranslucent(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
@@ -12920,6 +13050,20 @@
             }
         }
 
+        if (mActiveUids.size() > 0) {
+            if (needSep) {
+                pw.println();
+            }
+            pw.println("  UID states:");
+            for (int i=0; i<mActiveUids.size(); i++) {
+                UidRecord uidRec = mActiveUids.valueAt(i);
+                pw.print("    UID "); UserHandle.formatUid(pw, uidRec.uid);
+                pw.print(": "); pw.println(uidRec);
+            }
+            needSep = true;
+            printedAnything = true;
+        }
+
         if (mLruProcesses.size() > 0) {
             if (needSep) {
                 pw.println();
@@ -15162,7 +15306,7 @@
                 mAvailProcessChanges.add(item);
             }
         }
-        mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
+        mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
 
         // If the caller is restarting this app, then leave it in its
         // current lists and let the caller take care of it.
@@ -15173,8 +15317,7 @@
         if (!app.persistent || app.isolated) {
             if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                     "Removing non-persistent process during cleanup: " + app);
-            mProcessNames.remove(app.processName, app.uid);
-            mIsolatedProcesses.remove(app.uid);
+            removeProcessNameLocked(app.processName, app.uid);
             if (mHeavyWeightProcess == app) {
                 mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                         mHeavyWeightProcess.userId, 0));
@@ -15206,7 +15349,7 @@
             if (index < 0) {
                 ProcessList.remove(app.pid);
             }
-            mProcessNames.put(app.processName, app.uid, app);
+            addProcessNameLocked(app);
             startProcessLocked(app, "restart", app.processName);
             return true;
         } else if (app.pid > 0 && app.pid != MY_PID) {
@@ -18289,7 +18432,7 @@
                 if (NA > 0) {
                     item = mAvailProcessChanges.remove(NA-1);
                     if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Retreiving available item: " + item);
+                            "Retrieving available item: " + item);
                 } else {
                     item = new ProcessChangeItem();
                     if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
@@ -18301,7 +18444,7 @@
                 if (mPendingProcessChanges.size() == 0) {
                     if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                             "*** Enqueueing dispatch processes changed!");
-                    mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
+                    mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
                 }
                 mPendingProcessChanges.add(item);
             }
@@ -18320,6 +18463,31 @@
         return success;
     }
 
+    private final void enqueueUidChangeLocked(UidRecord uidRec, boolean gone) {
+        if (uidRec.pendingChange == null) {
+            if (mPendingUidChanges.size() == 0) {
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                        "*** Enqueueing dispatch uid changed!");
+                mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED).sendToTarget();
+            }
+            final int NA = mAvailUidChanges.size();
+            if (NA > 0) {
+                uidRec.pendingChange = mAvailUidChanges.remove(NA-1);
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                        "Retrieving available item: " + uidRec.pendingChange);
+            } else {
+                uidRec.pendingChange = new UidRecord.ChangeItem();
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                        "Allocating new item: " + uidRec.pendingChange);
+            }
+            uidRec.pendingChange.uidRecord = uidRec;
+            uidRec.pendingChange.uid = uidRec.uid;
+            mPendingUidChanges.add(uidRec.pendingChange);
+        }
+        uidRec.pendingChange.gone = gone;
+        uidRec.pendingChange.processState = uidRec.setProcState;
+    }
+
     private void maybeUpdateUsageStats(ProcessRecord app) {
         if (DEBUG_USAGE_STATS) {
             Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
@@ -18463,6 +18631,14 @@
             Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
         }
 
+        // Reset state in all uid records.
+        for (int i=mActiveUids.size()-1; i>=0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                    "Starting update of " + uidRec);
+            uidRec.reset();
+        }
+
         mAdjSeq++;
         mNewNumServiceProcs = 0;
         mNewNumAServiceProcs = 0;
@@ -18610,6 +18786,12 @@
                     // good to avoid having whatever code was running in them
                     // left sitting around after no longer needed.
                     app.kill("isolated not needed", true);
+                } else {
+                    // Keeping this process, update its uid.
+                    final UidRecord uidRec = app.uidRecord;
+                    if (uidRec != null && uidRec.curProcState > app.curProcState) {
+                        uidRec.curProcState = app.curProcState;
+                    }
                 }
 
                 if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
@@ -18805,6 +18987,18 @@
             requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
         }
 
+        // Update from any uid changes.
+        for (int i=mActiveUids.size()-1; i>=0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (uidRec.setProcState != uidRec.curProcState) {
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                        "Changes in " + uidRec + ": proc state from " + uidRec.setProcState
+                        + " to " + uidRec.curProcState);
+                uidRec.setProcState = uidRec.curProcState;
+                enqueueUidChangeLocked(uidRec, false);
+            }
+        }
+
         if (mProcessStats.shouldWriteNowLocked(now)) {
             mHandler.post(new Runnable() {
                 @Override public void run() {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 29e14f8..14759c3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -62,8 +62,8 @@
     final int userId;           // user of process.
     final String processName;   // name of the process
     // List of packages running in the process
-    final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList
-            = new ArrayMap<String, ProcessStats.ProcessStateHolder>();
+    final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>();
+    UidRecord uidRecord;        // overall state of process's uid.
     ArraySet<String> pkgDeps;   // additional packages we have a dependency on
     IApplicationThread thread;  // the actual proc...  may be null only if
                                 // 'persistent' is true (in which case we
@@ -142,24 +142,20 @@
     Object adjTarget;           // Debugging: target component impacting oom_adj.
     Runnable crashHandler;      // Optional local handler to be invoked in the process crash.
 
-    // contains HistoryRecord objects
-    final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+    // all activities running in the process
+    final ArrayList<ActivityRecord> activities = new ArrayList<>();
     // all ServiceRecord running in this process
-    final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>();
+    final ArraySet<ServiceRecord> services = new ArraySet<>();
     // services that are currently executing code (need to remain foreground).
-    final ArraySet<ServiceRecord> executingServices
-             = new ArraySet<ServiceRecord>();
+    final ArraySet<ServiceRecord> executingServices = new ArraySet<>();
     // All ConnectionRecord this process holds
-    final ArraySet<ConnectionRecord> connections
-            = new ArraySet<ConnectionRecord>();
+    final ArraySet<ConnectionRecord> connections = new ArraySet<>();
     // all IIntentReceivers that are registered from this process.
-    final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>();
+    final ArraySet<ReceiverList> receivers = new ArraySet<>();
     // class (String) -> ContentProviderRecord
-    final ArrayMap<String, ContentProviderRecord> pubProviders
-            = new ArrayMap<String, ContentProviderRecord>();
+    final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
     // All ContentProviderRecord process is using
-    final ArrayList<ContentProviderConnection> conProviders
-            = new ArrayList<ContentProviderConnection>();
+    final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();
 
     boolean execServicesFg;     // do we need to be executing services in the foreground?
     boolean persistent;         // always keep this application running?
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
new file mode 100644
index 0000000..b4efbf0
--- /dev/null
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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.am;
+
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+/**
+ * Overall information about a uid that has actively running processes.
+ */
+public final class UidRecord {
+    final int uid;
+    int curProcState;
+    int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+    int numProcs;
+
+    static final class ChangeItem {
+        UidRecord uidRecord;
+        int uid;
+        boolean gone;
+        int processState;
+    }
+
+    ChangeItem pendingChange;
+
+    public UidRecord(int _uid) {
+        uid = _uid;
+        reset();
+    }
+
+    public void reset() {
+        curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("UidRecord{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        UserHandle.formatUid(sb, uid);
+        sb.append(' ');
+        sb.append(ProcessList.makeProcStateString(curProcState));
+        sb.append(" / ");
+        sb.append(numProcs);
+        sb.append(" procs}");
+        return sb.toString();
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 4e83992..fba9258 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -149,7 +149,6 @@
     /**
      * Force evaluation even if it has succeeded in the past.
      * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     * arg2 = Number of evaluation attempts to make. (If 0, make INITIAL_ATTEMPTS attempts.)
      */
     public static final int CMD_FORCE_REEVALUATION = BASE + 8;
 
@@ -183,20 +182,18 @@
     private final int mLingerDelayMs;
     private int mLingerToken = 0;
 
-    // Negative values disable reevaluation.
-    private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay";
-    // When connecting, attempt to validate 3 times, pausing 5s between them.
-    private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000;
-    private static final int INITIAL_ATTEMPTS = 3;
-    // If a network is not validated, make one attempt every 10 mins to see if it starts working.
-    private static final int REEVALUATE_PAUSE_MS = 10*60*1000;
-    private static final int PERIODIC_ATTEMPTS = 1;
-    // When an application calls reportNetworkConnectivity, only make one attempt.
-    private static final int REEVALUATE_ATTEMPTS = 1;
-    private final int mReevaluateDelayMs;
+    // Start mReevaluateDelayMs at this value and double.
+    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
+    private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000;
+    // Before network has been evaluated this many times, ignore repeated reevaluate requests.
+    private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
     private int mReevaluateToken = 0;
     private static final int INVALID_UID = -1;
     private int mUidResponsibleForReeval = INVALID_UID;
+    // When network has been evaluated this many times:
+    //   1. report NETWORK_TEST_RESULT_INVALID
+    //   2. stop blaming UID that requested re-evaluation for further attempts
+    private static final int INITIAL_EVALUATION_ATTEMPTS = 3;
 
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
@@ -211,19 +208,12 @@
 
     // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
     private boolean mUserDoesNotWant = false;
-
-    // How many times we should attempt validation. Only checked in EvaluatingState; must be set
-    // before entering EvaluatingState. Note that whatever code causes us to transition to
-    // EvaluatingState last decides how many attempts will be made, so if one codepath were to
-    // enter EvaluatingState with a specific number of attempts, and then another were to enter it
-    // with a different number of attempts, the second number would be used. This is not currently
-    // a problem because EvaluatingState is not reentrant.
-    private int mMaxAttempts;
+    // Avoids surfacing "Sign in to network" notification.
+    private boolean mDontDisplaySigninNotification = false;
 
     public boolean systemReady = false;
 
     private final State mDefaultState = new DefaultState();
-    private final State mOfflineState = new OfflineState();
     private final State mValidatedState = new ValidatedState();
     private final State mMaybeNotifyState = new MaybeNotifyState();
     private final State mEvaluatingState = new EvaluatingState();
@@ -247,7 +237,6 @@
         mDefaultRequest = defaultRequest;
 
         addState(mDefaultState);
-        addState(mOfflineState, mDefaultState);
         addState(mValidatedState, mDefaultState);
         addState(mMaybeNotifyState, mDefaultState);
             addState(mEvaluatingState, mMaybeNotifyState);
@@ -260,8 +249,6 @@
         if (mServer == null) mServer = DEFAULT_SERVER;
 
         mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
-        mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY,
-                DEFAULT_REEVALUATE_DELAY_MS);
 
         mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
@@ -289,7 +276,6 @@
                     return HANDLED;
                 case CMD_NETWORK_CONNECTED:
                     if (DBG) log("Connected");
-                    mMaxAttempts = INITIAL_ATTEMPTS;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
@@ -303,7 +289,6 @@
                 case CMD_FORCE_REEVALUATION:
                     if (DBG) log("Forcing reevaluation");
                     mUidResponsibleForReeval = message.arg1;
-                    mMaxAttempts = message.arg2 != 0 ? message.arg2 : REEVALUATE_ATTEMPTS;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_CAPTIVE_PORTAL_APP_FINISHED:
@@ -313,18 +298,23 @@
                     mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong());
                     switch (message.arg1) {
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_DISMISSED:
-                            sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */,
-                                    0 /* INITIAL_ATTEMPTS */);
+                            sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */, 0);
                             break;
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS:
+                            mDontDisplaySigninNotification = true;
                             // TODO: Distinguish this from a network that actually validates.
                             // Displaying the "!" on the system UI icon may still be a good idea.
                             transitionTo(mValidatedState);
                             break;
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_UNWANTED:
+                            mDontDisplaySigninNotification = true;
                             mUserDoesNotWant = true;
+                            mConnectivityServiceHandler.sendMessage(obtainMessage(
+                                    EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
+                                    mNetworkAgentInfo));
                             // TODO: Should teardown network.
-                            transitionTo(mOfflineState);
+                            mUidResponsibleForReeval = 0;
+                            transitionTo(mEvaluatingState);
                             break;
                     }
                     return HANDLED;
@@ -334,42 +324,6 @@
         }
     }
 
-    // Being in the OfflineState State indicates a Network is unwanted or failed validation.
-    private class OfflineState extends State {
-        @Override
-        public void enter() {
-            mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                    NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
-            if (!mUserDoesNotWant) {
-                sendMessageDelayed(CMD_FORCE_REEVALUATION, 0 /* no UID */,
-                        PERIODIC_ATTEMPTS, REEVALUATE_PAUSE_MS);
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString());
-                        switch (message.what) {
-                case CMD_FORCE_REEVALUATION:
-                    // If the user has indicated they explicitly do not want to use this network,
-                    // don't allow a reevaluation as this will be pointless and could result in
-                    // the user being annoyed with repeated unwanted notifications.
-                    return mUserDoesNotWant ? HANDLED : NOT_HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-             // NOTE: This removes the delayed message posted by enter() but will inadvertently
-             // remove any other CMD_FORCE_REEVALUATION in the message queue.  At the moment this
-             // is harmless.  If in the future this becomes problematic a different message could
-             // be used.
-             removeMessages(CMD_FORCE_REEVALUATION);
-        }
-    }
-
     // Being in the ValidatedState State indicates a Network is:
     // - Successfully validated, or
     // - Wanted "as is" by the user, or
@@ -426,18 +380,20 @@
     }
 
     // Being in the EvaluatingState State indicates the Network is being evaluated for internet
-    // connectivity.
+    // connectivity, or that the user has indicated that this network is unwanted.
     private class EvaluatingState extends State {
-        private int mAttempt;
+        private int mReevaluateDelayMs;
+        private int mAttempts;
 
         @Override
         public void enter() {
-            mAttempt = 1;
             sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
             if (mUidResponsibleForReeval != INVALID_UID) {
                 TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
                 mUidResponsibleForReeval = INVALID_UID;
             }
+            mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
+            mAttempts = 0;
         }
 
         @Override
@@ -445,7 +401,7 @@
             if (DBG) log(getName() + message.toString());
             switch (message.what) {
                 case CMD_REEVALUATE:
-                    if (message.arg1 != mReevaluateToken)
+                    if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
                         return HANDLED;
                     // Don't bother validating networks that don't satisify the default request.
                     // This includes:
@@ -469,6 +425,7 @@
                         transitionTo(mValidatedState);
                         return HANDLED;
                     }
+                    mAttempts++;
                     // Note: This call to isCaptivePortal() could take up to a minute. Resolving the
                     // server's IP addresses could hit the DNS timeout, and attempting connections
                     // to each of the server's several IP addresses (currently one IPv4 and one
@@ -480,16 +437,27 @@
                         transitionTo(mValidatedState);
                     } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
                         transitionTo(mCaptivePortalState);
-                    } else if (++mAttempt > mMaxAttempts) {
-                        transitionTo(mOfflineState);
-                    } else if (mReevaluateDelayMs >= 0) {
+                    } else {
                         Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
                         sendMessageDelayed(msg, mReevaluateDelayMs);
+                        if (mAttempts >= INITIAL_EVALUATION_ATTEMPTS) {
+                            mConnectivityServiceHandler.sendMessage(obtainMessage(
+                                    EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
+                                    mNetworkAgentInfo));
+                            // Don't continue to blame UID forever.
+                            TrafficStats.clearThreadStatsUid();
+                        }
+                        mReevaluateDelayMs *= 2;
+                        if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
+                            mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
+                        }
                     }
                     return HANDLED;
                 case CMD_FORCE_REEVALUATION:
-                    // Ignore duplicate requests.
-                    return HANDLED;
+                    // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
+                    // ignore any re-evaluation requests. After, restart the
+                    // evaluation process via EvaluatingState#enter.
+                    return mAttempts < IGNORE_REEVALUATE_ATTEMPTS ? HANDLED : NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -533,6 +501,8 @@
         public void enter() {
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
+            // Don't annoy user with sign-in notifications.
+            if (mDontDisplaySigninNotification) return;
             // Create a CustomIntentReceiver that sends us a
             // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
             // touches the notification.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index aeecdf3..e1ec8a6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -298,13 +298,15 @@
     }
 
     /**
-     * Set whether the current package has the ability to launch VPNs without user intervention.
+     * Set whether a package has the ability to launch VPNs without user intervention.
      */
-    public void setPackageAuthorization(boolean authorized) {
+    public void setPackageAuthorization(String packageName, boolean authorized) {
         // Check if the caller is authorized.
         enforceControlPermission();
 
-        if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
+        int uid = getAppUid(packageName, mUserHandle);
+        if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
+            // Authorization for nonexistent packages (or fake ones) can't be updated.
             return;
         }
 
@@ -312,10 +314,10 @@
         try {
             AppOpsManager appOps =
                     (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
+            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
                     authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
         } catch (Exception e) {
-            Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
+            Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index e516573..517a825 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.content.res.Resources;
+import android.os.Build;
 import com.android.server.LocalServices;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
@@ -50,6 +51,8 @@
 
     private static final String UNIQUE_ID_PREFIX = "local:";
 
+    private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
+
     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
             SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
             SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
@@ -273,8 +276,9 @@
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
-                    if (res.getBoolean(
-                            com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)) {
+                    if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
+                            || (Build.HARDWARE.contains("goldfish")
+                            && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
                     mInfo.type = Display.TYPE_BUILT_IN;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 24ab3b8..1a79568 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -81,6 +81,7 @@
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.IProcessObserver;
+import android.app.IUidObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.usage.UsageStatsManagerInternal;
@@ -153,10 +154,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.AppOpsService;
 import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -294,9 +293,8 @@
     /** Set of currently active {@link Notification} tags. */
     private final ArraySet<String> mActiveNotifs = new ArraySet<String>();
 
-    /** Foreground at both UID and PID granularity. */
+    /** Foreground at UID granularity. */
     final SparseIntArray mUidState = new SparseIntArray();
-    final SparseArray<SparseIntArray> mUidPidState = new SparseArray<>();
 
     /** The current maximum process state that we are considering to be foreground. */
     private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP;
@@ -411,7 +409,7 @@
         updateScreenOn();
 
         try {
-            mActivityManager.registerProcessObserver(mProcessObserver);
+            mActivityManager.registerUidObserver(mUidObserver);
             mNetworkManager.registerObserver(mAlertObserver);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
@@ -477,40 +475,16 @@
 
     }
 
-    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
-        @Override
-        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
-        }
-
-        @Override
-        public void onProcessStateChanged(int pid, int uid, int procState) {
+    private IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
             synchronized (mRulesLock) {
-                // because a uid can have multiple pids running inside, we need to
-                // remember all pid states and summarize foreground at uid level.
-
-                // record foreground for this specific pid
-                SparseIntArray pidState = mUidPidState.get(uid);
-                if (pidState == null) {
-                    pidState = new SparseIntArray(2);
-                    mUidPidState.put(uid, pidState);
-                }
-                pidState.put(pid, procState);
-                computeUidStateLocked(uid);
+                updateUidStateLocked(uid, procState);
             }
         }
 
-        @Override
-        public void onProcessDied(int pid, int uid) {
+        @Override public void onUidGone(int uid) throws RemoteException {
             synchronized (mRulesLock) {
-                // clear records and recompute, when they exist
-                final SparseIntArray pidState = mUidPidState.get(uid);
-                if (pidState != null) {
-                    pidState.delete(pid);
-                    if (pidState.size() <= 0) {
-                        mUidPidState.remove(uid);
-                    }
-                    computeUidStateLocked(uid);
-                }
+                removeUidStateLocked(uid);
             }
         }
     };
@@ -1919,14 +1893,6 @@
                 fout.print(state);
                 fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)");
 
-                fout.print(" pids=");
-                final int foregroundIndex = mUidPidState.indexOfKey(uid);
-                if (foregroundIndex < 0) {
-                    fout.print("UNKNOWN");
-                } else {
-                    dumpSparseIntArray(fout, mUidPidState.valueAt(foregroundIndex));
-                }
-
                 fout.print(" rules=");
                 final int rulesIndex = mUidRules.indexOfKey(uid);
                 if (rulesIndex < 0) {
@@ -1957,36 +1923,38 @@
     }
 
     /**
-     * Process state of PID changed; recompute state at UID level. If
-     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
+     * Process state of UID changed; if needed, will trigger
+     * {@link #updateRulesForUidLocked(int)}.
      */
-    void computeUidStateLocked(int uid) {
-        final SparseIntArray pidState = mUidPidState.get(uid);
-
-        // current pid is dropping foreground; examine other pids
-        int uidState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-        if (pidState != null) {
-            final int size = pidState.size();
-            for (int i = 0; i < size; i++) {
-                final int state = pidState.valueAt(i);
-                if (state < uidState) {
-                    uidState = state;
-                }
-            }
-        }
-
+    void updateUidStateLocked(int uid, int uidState) {
         final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         if (oldUidState != uidState) {
             // state changed, push updated rules
             mUidState.put(uid, uidState);
-            final boolean oldForeground = oldUidState <= mCurForegroundState;
-            final boolean newForeground = uidState <= mCurForegroundState;
-            if (oldForeground != newForeground) {
-                updateRulesForUidLocked(uid);
+            updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
+        }
+    }
+
+    void removeUidStateLocked(int uid) {
+        final int index = mUidState.indexOfKey(uid);
+        if (index >= 0) {
+            final int oldUidState = mUidState.valueAt(index);
+            mUidState.removeAt(index);
+            if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
+                updateRulesForUidStateChangeLocked(uid, oldUidState,
+                        ActivityManager.PROCESS_STATE_CACHED_EMPTY);
             }
         }
     }
 
+    void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) {
+        final boolean oldForeground = oldUidState <= mCurForegroundState;
+        final boolean newForeground = newUidState <= mCurForegroundState;
+        if (oldForeground != newForeground) {
+            updateRulesForUidLocked(uid);
+        }
+    }
+
     private void updateScreenOn() {
         synchronized (mRulesLock) {
             try {
@@ -2381,16 +2349,6 @@
         }
     }
 
-    private static void dumpSparseIntArray(PrintWriter fout, SparseIntArray value) {
-        fout.print("[");
-        final int size = value.size();
-        for (int i = 0; i < size; i++) {
-            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
-            if (i < size - 1) fout.print(",");
-        }
-        fout.print("]");
-    }
-
     @Override
     public void factoryReset(String subscriber) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 509289b..28a786a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -369,11 +369,14 @@
     /** Permission grant: grant the permission as an install permission. */
     private static final int GRANT_INSTALL = 2;
 
+    /** Permission grant: grant the permission as an install permission for a legacy app. */
+    private static final int GRANT_INSTALL_LEGACY = 3;
+
     /** Permission grant: grant the permission as a runtime one. */
-    private static final int GRANT_RUNTIME = 3;
+    private static final int GRANT_RUNTIME = 4;
 
     /** Permission grant: grant as runtime a permission that was granted as an install time one. */
-    private static final int GRANT_UPGRADE = 4;
+    private static final int GRANT_UPGRADE = 5;
 
     final ServiceThread mHandlerThread;
 
@@ -4133,6 +4136,7 @@
 
         final int userId = UserHandle.getCallingUserId();
         ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
@@ -4155,27 +4159,22 @@
                     // Try to get the status from User settings first
                     int status = getDomainVerificationStatusLPr(ps, userId);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
-                        result.add(info);
+                        alwaysList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
                         neverList.add(info);
-                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
+                            status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
                         undefinedList.add(info);
                     }
                 }
             }
-            // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
-            result.addAll(undefinedList);
-            // If there is nothing selected, add all candidates and remove the ones that the User
-            // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state and
-            // also remove Browser Apps ones.
-            // If there is still none after this pass, add all Browser Apps and
-            // let the User decide with the Disambiguation dialog if there are several ones.
-            if (result.size() == 0) {
-                result.addAll(candidates);
-            }
-            result.removeAll(neverList);
-            result.removeAll(matchAllList);
-            if (result.size() == 0) {
+            // First try to add the "always" if there is any
+            if (alwaysList.size() > 0) {
+                result.addAll(alwaysList);
+            } else {
+                // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
+                result.addAll(undefinedList);
+                // Also add Browsers (all of them or only the default one)
                 if ((flags & MATCH_ALL) != 0) {
                     result.addAll(matchAllList);
                 } else {
@@ -4200,6 +4199,13 @@
                         result.addAll(matchAllList);
                     }
                 }
+
+                // If there is nothing selected, add all candidates and remove the ones that the User
+                // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state
+                if (result.size() == 0) {
+                    result.addAll(candidates);
+                    result.removeAll(neverList);
+                }
             }
         }
         if (DEBUG_PREFERRED) {
@@ -6301,7 +6307,6 @@
         }
 
         final String path = scanFile.getPath();
-        final String codePath = pkg.applicationInfo.getCodePath();
         final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
         if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
             setBundledAppAbisAndRoots(pkg, pkgSetting);
@@ -6327,127 +6332,27 @@
 
             setNativeLibraryPaths(pkg);
         } else {
-            // TODO: We can probably be smarter about this stuff. For installed apps,
-            // we can calculate this information at install time once and for all. For
-            // system apps, we can probably assume that this information doesn't change
-            // after the first boot scan. As things stand, we do lots of unnecessary work.
+            if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
+                deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
+            } else {
+                // Verify the ABIs haven't changed since we last deduced them.
+                String oldPrimaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
+                String oldSecondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
 
-            // Give ourselves some initial paths; we'll come back for another
-            // pass once we've determined ABI below.
-            setNativeLibraryPaths(pkg);
-
-            final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
-            final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
-            final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
-            NativeLibraryHelper.Handle handle = null;
-            try {
-                handle = NativeLibraryHelper.Handle.create(scanFile);
-                // TODO(multiArch): This can be null for apps that didn't go through the
-                // usual installation process. We can calculate it again, like we
-                // do during install time.
-                //
-                // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
-                // unnecessary.
-                final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
-                // Null out the abis so that they can be recalculated.
-                pkg.applicationInfo.primaryCpuAbi = null;
-                pkg.applicationInfo.secondaryCpuAbi = null;
-                if (isMultiArch(pkg.applicationInfo)) {
-                    // Warn if we've set an abiOverride for multi-lib packages..
-                    // By definition, we need to copy both 32 and 64 bit libraries for
-                    // such packages.
-                    if (pkg.cpuAbiOverride != null
-                            && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
-                        Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
-                    }
-
-                    int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
-                    int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
-                    if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-                        if (isAsec) {
-                            abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
-                        } else {
-                            abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                    nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
-                                    useIsaSpecificSubdirs);
-                        }
-                    }
-
-                    maybeThrowExceptionForMultiArchCopy(
-                            "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
-                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-                        if (isAsec) {
-                            abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
-                        } else {
-                            abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                    nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
-                                    useIsaSpecificSubdirs);
-                        }
-                    }
-
-                    maybeThrowExceptionForMultiArchCopy(
-                            "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
-                    if (abi64 >= 0) {
-                        pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
-                    }
-
-                    if (abi32 >= 0) {
-                        final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
-                        if (abi64 >= 0) {
-                            pkg.applicationInfo.secondaryCpuAbi = abi;
-                        } else {
-                            pkg.applicationInfo.primaryCpuAbi = abi;
-                        }
-                    }
-                } else {
-                    String[] abiList = (cpuAbiOverride != null) ?
-                            new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
-                    // Enable gross and lame hacks for apps that are built with old
-                    // SDK tools. We must scan their APKs for renderscript bitcode and
-                    // not launch them if it's present. Don't bother checking on devices
-                    // that don't have 64 bit support.
-                    boolean needsRenderScriptOverride = false;
-                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
-                            NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
-                        abiList = Build.SUPPORTED_32_BIT_ABIS;
-                        needsRenderScriptOverride = true;
-                    }
-
-                    final int copyRet;
-                    if (isAsec) {
-                        copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
-                    } else {
-                        copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
-                    }
-
-                    if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
-                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Error unpackaging native libs for app, errorCode=" + copyRet);
-                    }
-
-                    if (copyRet >= 0) {
-                        pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
-                    } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
-                        pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
-                    } else if (needsRenderScriptOverride) {
-                        pkg.applicationInfo.primaryCpuAbi = abiList[0];
-                    }
+                // TODO: The only purpose of this code is to update the native library paths
+                // based on the final install location. We can simplify this and avoid having
+                // to scan the package again.
+                deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, false /* extract libs */);
+                if (!TextUtils.equals(oldPrimaryCpuAbi, pkg.applicationInfo.primaryCpuAbi)) {
+                    throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
+                            + oldPrimaryCpuAbi + "-> " + pkg.applicationInfo.primaryCpuAbi);
                 }
-            } catch (IOException ioe) {
-                Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
-            } finally {
-                IoUtils.closeQuietly(handle);
-            }
 
-            // Now that we've calculated the ABIs and determined if it's an internal app,
-            // we will go ahead and populate the nativeLibraryPath.
-            setNativeLibraryPaths(pkg);
+                if (!TextUtils.equals(oldSecondaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi)) {
+                    throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
+                            + oldSecondaryCpuAbi + "-> " + pkg.applicationInfo.secondaryCpuAbi);
+                }
+            }
 
             if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
             final int[] userIds = sUserManager.getUserIds();
@@ -6478,9 +6383,21 @@
                     Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
         }
 
+        // If there's a mismatch between the abi-override in the package setting
+        // and the abiOverride specified for the install. Warn about this because we
+        // would've already compiled the app without taking the package setting into
+        // account.
+        if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
+            if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
+                Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
+                        " for package: " + pkg.packageName);
+            }
+        }
+
         pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
         pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
+
         // Copy the derived override back to the parsed package, so that we can
         // update the package settings accordingly.
         pkg.cpuAbiOverride = cpuAbiOverride;
@@ -6974,6 +6891,144 @@
     }
 
     /**
+     * Derive the ABI of a non-system package located at {@code scanFile}. This information
+     * is derived purely on the basis of the contents of {@code scanFile} and
+     * {@code cpuAbiOverride}.
+     *
+     * If {@code extractLibs} is true, native libraries are extracted from the app if required.
+     */
+    public void deriveNonSystemPackageAbi(PackageParser.Package pkg, File scanFile,
+                                          String cpuAbiOverride, boolean extractLibs)
+            throws PackageManagerException {
+        // TODO: We can probably be smarter about this stuff. For installed apps,
+        // we can calculate this information at install time once and for all. For
+        // system apps, we can probably assume that this information doesn't change
+        // after the first boot scan. As things stand, we do lots of unnecessary work.
+
+        // Give ourselves some initial paths; we'll come back for another
+        // pass once we've determined ABI below.
+        setNativeLibraryPaths(pkg);
+
+        // We would never need to extract libs for forward-locked and external packages,
+        // since the container service will do it for us.
+        if (pkg.isForwardLocked() || isExternal(pkg)) {
+            extractLibs = false;
+        }
+
+        final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
+        final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
+
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = NativeLibraryHelper.Handle.create(scanFile);
+            // TODO(multiArch): This can be null for apps that didn't go through the
+            // usual installation process. We can calculate it again, like we
+            // do during install time.
+            //
+            // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+            // unnecessary.
+            final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+            // Null out the abis so that they can be recalculated.
+            pkg.applicationInfo.primaryCpuAbi = null;
+            pkg.applicationInfo.secondaryCpuAbi = null;
+            if (isMultiArch(pkg.applicationInfo)) {
+                // Warn if we've set an abiOverride for multi-lib packages..
+                // By definition, we need to copy both 32 and 64 bit libraries for
+                // such packages.
+                if (pkg.cpuAbiOverride != null
+                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+                    Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
+                }
+
+                int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+                int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
+                    }
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
+                    }
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+                if (abi64 >= 0) {
+                    pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+                }
+
+                if (abi32 >= 0) {
+                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+                    if (abi64 >= 0) {
+                        pkg.applicationInfo.secondaryCpuAbi = abi;
+                    } else {
+                        pkg.applicationInfo.primaryCpuAbi = abi;
+                    }
+                }
+            } else {
+                String[] abiList = (cpuAbiOverride != null) ?
+                        new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
+
+                // Enable gross and lame hacks for apps that are built with old
+                // SDK tools. We must scan their APKs for renderscript bitcode and
+                // not launch them if it's present. Don't bother checking on devices
+                // that don't have 64 bit support.
+                boolean needsRenderScriptOverride = false;
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
+                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                    needsRenderScriptOverride = true;
+                }
+
+                final int copyRet;
+                if (extractLibs) {
+                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                } else {
+                    copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+                }
+
+                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Error unpackaging native libs for app, errorCode=" + copyRet);
+                }
+
+                if (copyRet >= 0) {
+                    pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
+                } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
+                    pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
+                } else if (needsRenderScriptOverride) {
+                    pkg.applicationInfo.primaryCpuAbi = abiList[0];
+                }
+            }
+        } catch (IOException ioe) {
+            Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
+        } finally {
+            IoUtils.closeQuietly(handle);
+        }
+
+        // Now that we've calculated the ABIs and determined if it's an internal app,
+        // we will go ahead and populate the nativeLibraryPath.
+        setNativeLibraryPaths(pkg);
+    }
+
+    /**
      * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
      * i.e, so that all packages can be run inside a single process if required.
      *
@@ -7689,7 +7744,7 @@
                 case PermissionInfo.PROTECTION_DANGEROUS: {
                     if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                         // For legacy apps dangerous permissions are install time ones.
-                        grant = GRANT_INSTALL;
+                        grant = GRANT_INSTALL_LEGACY;
                     } else if (ps.isSystem()) {
                         final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds();
                         if (origPermissions.hasInstallPermission(bp.name)) {
@@ -7749,6 +7804,28 @@
 
                 switch (grant) {
                     case GRANT_INSTALL: {
+                        // Revoke this as runtime permission to handle the case of
+                        // a runtime permssion being downgraded to an install one.
+                        for (int userId : UserManagerService.getInstance().getUserIds()) {
+                            if (origPermissions.getRuntimePermissionState(
+                                    bp.name, userId) != null) {
+                                // Revoke the runtime permission and clear the flags.
+                                origPermissions.revokeRuntimePermission(bp, userId);
+                                origPermissions.updatePermissionFlags(bp, userId,
+                                      PackageManager.MASK_PERMISSION_FLAGS, 0);
+                                // If we revoked a permission permission, we have to write.
+                                changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+                                        changedRuntimePermissionUserIds, userId);
+                            }
+                        }
+                        // Grant an install permission.
+                        if (permissionsState.grantInstallPermission(bp) !=
+                                PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                            changedInstallPermission = true;
+                        }
+                    } break;
+
+                    case GRANT_INSTALL_LEGACY: {
                         // Grant an install permission.
                         if (permissionsState.grantInstallPermission(bp) !=
                                 PermissionsState.PERMISSION_OPERATION_FAILURE) {
@@ -11566,6 +11643,16 @@
         } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
             // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
             scanFlags |= SCAN_NO_DEX;
+
+            try {
+                deriveNonSystemPackageAbi(pkg, new File(pkg.codePath), args.abiOverride,
+                        true /* extract libs */);
+            } catch (PackageManagerException pme) {
+                Slog.e(TAG, "Error deriving application ABI", pme);
+                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error ");
+                return;
+            }
+
             // Run dexopt before old package gets removed, to minimize time when app is unavailable
             int result = mPackageDexOptimizer
                     .performDexOpt(pkg, null /* instruction sets */, true /* forceDex */,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 40c8ca3..15d1535a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -580,6 +580,28 @@
      * Check if we've hit the limit of how many users can be created.
      */
     private boolean isUserLimitReachedLocked() {
+        return getAliveUsersExcludingGuestsCountLocked() >= UserManager.getMaxSupportedUsers();
+    }
+
+    @Override
+    public boolean canAddMoreManagedProfiles() {
+        checkManageUsersPermission("check if more managed profiles can be added.");
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            return false;
+        }
+        synchronized(mPackagesLock) {
+            // Limit number of managed profiles that can be created
+            if (numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
+                    >= MAX_MANAGED_PROFILES) {
+                return false;
+            }
+            int usersCount = getAliveUsersExcludingGuestsCountLocked();
+            // We allow creating a managed profile in the special case where there is only one user.
+            return usersCount == 1 || usersCount < UserManager.getMaxSupportedUsers();
+        }
+    }
+
+    private int getAliveUsersExcludingGuestsCountLocked() {
         int aliveUserCount = 0;
         final int totalUserCount = mUsers.size();
         // Skip over users being removed
@@ -590,7 +612,7 @@
                 aliveUserCount++;
             }
         }
-        return aliveUserCount >= UserManager.getMaxSupportedUsers();
+        return aliveUserCount;
     }
 
     /**
@@ -1176,7 +1198,11 @@
             Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
             return null;
         }
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            return null;
+        }
         final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
+        final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         try {
@@ -1187,21 +1213,18 @@
                         parent = getUserInfoLocked(parentId);
                         if (parent == null) return null;
                     }
-                    // If we're not adding a guest user and the limit has been reached,
-                    // cannot add a user.
-                    if (!isGuest && isUserLimitReachedLocked()) {
+                    if (isManagedProfile && !canAddMoreManagedProfiles()) {
+                        return null;
+                    }
+                    if (!isGuest && !isManagedProfile && isUserLimitReachedLocked()) {
+                        // If we're not adding a guest user or a managed profile and the limit has
+                        // been reached, cannot add a user.
                         return null;
                     }
                     // If we're adding a guest and there already exists one, bail.
                     if (isGuest && findCurrentGuestUserLocked() != null) {
                         return null;
                     }
-                    // Limit number of managed profiles that can be created
-                    if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0
-                            && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
-                                >= MAX_MANAGED_PROFILES) {
-                        return null;
-                    }
                     int userId = getNextAvailableIdLocked();
                     userInfo = new UserInfo(userId, name, null, flags);
                     File userPath = new File(mBaseUserPath, Integer.toString(userId));
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 185ef03..a4e9c68 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1220,9 +1220,7 @@
     };
 
     private boolean isRoundWindow() {
-        return mContext.getResources().getBoolean(com.android.internal.R.bool.config_windowIsRound)
-                || (Build.HARDWARE.contains("goldfish")
-                && SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false));
+        return mContext.getResources().getConfiguration().isScreenRound();
     }
 
     /** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 74df0a0..5aea746 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import android.app.ActivityManager;
+import android.util.SparseIntArray;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
@@ -436,6 +438,8 @@
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
+    private final SparseIntArray mUidState = new SparseIntArray();
+
     // True if theater mode is enabled
     private boolean mTheaterModeEnabled;
 
@@ -2316,6 +2320,24 @@
         }
     }
 
+    void updateUidProcStateInternal(int uid, int procState) {
+        synchronized (mLock) {
+            mUidState.put(uid, procState);
+            if (mDeviceIdleMode) {
+                updateWakeLockDisabledStatesLocked();
+            }
+        }
+    }
+
+    void uidGoneInternal(int uid) {
+        synchronized (mLock) {
+            mUidState.delete(uid);
+            if (mDeviceIdleMode) {
+                updateWakeLockDisabledStatesLocked();
+            }
+        }
+    }
+
     private void updateWakeLockDisabledStatesLocked() {
         boolean changed = false;
         final int numWakeLocks = mWakeLocks.size();
@@ -2349,7 +2371,10 @@
                 // If we are in idle mode, we will ignore all partial wake locks that are
                 // for application uids that are not whitelisted.
                 if (appid >= Process.FIRST_APPLICATION_UID &&
-                        Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0) {
+                        Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
+                        mUidState.get(wakeLock.mOwnerUid,
+                                ActivityManager.PROCESS_STATE_CACHED_EMPTY)
+                                > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                     disabled = true;
                 }
             }
@@ -2650,6 +2675,13 @@
             pw.println("Screen dim duration: " + screenDimDuration + " ms");
 
             pw.println();
+            pw.println("UID states:");
+            for (int i=0; i<mUidState.size(); i++) {
+                pw.print("  UID "); UserHandle.formatUid(pw, mUidState.keyAt(i));
+                pw.print(": "); pw.println(mUidState.valueAt(i));
+            }
+
+            pw.println();
             pw.println("Wake Locks: size=" + mWakeLocks.size());
             for (WakeLock wl : mWakeLocks) {
                 pw.println("  " + wl);
@@ -3451,5 +3483,15 @@
         public void setDeviceIdleWhitelist(int[] appids) {
             setDeviceIdleWhitelistInternal(appids);
         }
+
+        @Override
+        public void updateUidProcState(int uid, int procState) {
+            updateUidProcStateInternal(uid, procState);
+        }
+
+        @Override
+        public void uidGone(int uid) {
+            uidGoneInternal(uid);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 91ce739..482ae24 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -432,8 +432,7 @@
                 mDrawBorderInset = (int) mBorderWidth / 2;
                 mWindow = new ViewportWindow(mContext);
 
-                if (mContext.getResources().getBoolean(
-                            com.android.internal.R.bool.config_windowIsRound)) {
+                if (mContext.getResources().getConfiguration().isScreenRound()) {
                     mCircularPath = new Path();
                     mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
                     final int centerXY = mTempPoint.x / 2;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 0357de2..60bbc48 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -325,8 +325,7 @@
         mListeners.add(listener);
     }
 
-    public void notifyAppTransitionFinishedLocked(AppWindowAnimator animator) {
-        IBinder token = animator != null ? animator.mAppToken.token : null;
+    public void notifyAppTransitionFinishedLocked(IBinder token) {
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onAppTransitionFinishedLocked(token);
         }
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 3feec82..2e89385 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -345,7 +345,7 @@
         for (int i = 0; i < numAllAppWinAnimators; i++) {
             mAllAppWinAnimators.get(i).finishExit();
         }
-        mService.mAppTransition.notifyAppTransitionFinishedLocked(this);
+        mService.mAppTransition.notifyAppTransitionFinishedLocked(mAppToken.token);
         return false;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e43861c..d956d76 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -252,11 +252,6 @@
     static final int LAYER_OFFSET_DIM = 1;
 
     /**
-     * Blur surface layer is immediately below dim layer.
-     */
-    static final int LAYER_OFFSET_BLUR = 2;
-
-    /**
      * FocusedStackFrame layer is immediately above focused window.
      */
     static final int LAYER_OFFSET_FOCUSED_STACK = 1;
@@ -266,27 +261,12 @@
      * the thumbnail (or in other words as far as possible above the window
      * below it).
      */
-    static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER-1;
-
-    /**
-     * Layer at which to put the rotation freeze snapshot.
-     */
-    static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1;
-
-    /**
-     * Layer at which to put the mask for emulated screen sizes.
-     */
-    static final int MASK_LAYER = TYPE_LAYER_MULTIPLIER * 200;
+    static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER - 1;
 
     /** The maximum length we will accept for a loaded animation duration:
      * this is 10 seconds.
      */
-    static final int MAX_ANIMATION_DURATION = 10*1000;
-
-    /** Amount of time (in milliseconds) to animate the fade-in-out transition for
-     * compatible windows.
-     */
-    static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
+    static final int MAX_ANIMATION_DURATION = 10 * 1000;
 
     /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
     static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
@@ -381,48 +361,43 @@
     /**
      * All currently active sessions with clients.
      */
-    final ArraySet<Session> mSessions = new ArraySet<Session>();
+    final ArraySet<Session> mSessions = new ArraySet<>();
 
     /**
      * Mapping from an IWindow IBinder to the server's Window object.
      * This is also used as the lock for all of our state.
      * NOTE: Never call into methods that lock ActivityManagerService while holding this object.
      */
-    final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
+    final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
 
     /**
      * Mapping from a token IBinder to a WindowToken object.
      */
-    final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();
+    final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<>();
 
     /**
      * List of window tokens that have finished starting their application,
      * and now need to have the policy remove their windows.
      */
-    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
+    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
 
     /**
      * Fake windows added to the window manager.  Note: ordered from top to
      * bottom, opposite of mWindows.
      */
-    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>();
+    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<>();
 
     /**
      * Windows that are being resized.  Used so we can tell the client about
      * the resize after closing the transaction in which we resized the
      * underlying surface.
      */
-    final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
+    final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
 
     /**
      * Windows whose animations have ended and now must be removed.
      */
-    final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
-
-    /**
-     * Stacks whose animations have ended and whose tasks, apps, selves may now be removed.
-     */
-    final ArraySet<TaskStack> mPendingStacksRemove = new ArraySet<TaskStack>();
+    final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
 
     /**
      * Used when processing mPendingRemove to avoid working on the original array.
@@ -432,13 +407,13 @@
     /**
      * Windows whose surface should be destroyed.
      */
-    final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
+    final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
 
     /**
      * Windows that have lost input focus and are waiting for the new
      * focus window to be displayed before they are told about this.
      */
-    ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
+    ArrayList<WindowState> mLosingFocus = new ArrayList<>();
 
     /**
      * This is set when we have run out of memory, and will either be an empty
@@ -449,7 +424,7 @@
     /**
      * Windows that clients are waiting to have drawn.
      */
-    ArrayList<WindowState> mWaitingForDrawn = new ArrayList<WindowState>();
+    ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
     /**
      * And the callback to make when they've all been drawn.
      */
@@ -466,7 +441,7 @@
      * This array is essentially a cache for all userId for
      * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
      */
-    SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<Boolean>();
+    SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<>();
 
     IInputMethodManager mInputMethodManager;
 
@@ -840,8 +815,7 @@
     boolean mInTouchMode;
 
     private ViewServer mViewServer;
-    private final ArrayList<WindowChangeListener> mWindowChangeListeners =
-        new ArrayList<WindowChangeListener>();
+    private final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
     private boolean mWindowsChanged = false;
 
     public interface WindowChangeListener {
@@ -859,6 +833,10 @@
     // For example, when this flag is true, there will be no wallpaper service.
     final boolean mOnlyCore;
 
+    // List of clients without a transtiton animation that we notify once we are done transitioning
+    // since they won't be notified through the app window animator.
+    private final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
+
     /** Listener to notify activity manager about app transitions. */
     private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
             = new WindowManagerInternal.AppTransitionListener() {
@@ -3209,10 +3187,13 @@
                     }
                 }
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
-                    // To change the format, we need to re-build the surface.
-                    winAnimator.destroySurfaceLocked();
-                    toBeDisplayed = true;
-                    surfaceChanged = true;
+                    // If the format can be changed in place yaay!
+                    // If not, fall back to a surface re-build
+                    if (!winAnimator.tryChangeFormatInPlaceLocked()) {
+                        winAnimator.destroySurfaceLocked();
+                        toBeDisplayed = true;
+                        surfaceChanged = true;
+                    }
                 }
                 try {
                     if (!win.mHasSurface) {
@@ -5923,8 +5904,7 @@
 
     public void updateCircularDisplayMaskIfNeeded() {
         // we're fullscreen and not hosted in an ActivityView
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_windowIsRound)
+        if (mContext.getResources().getConfiguration().isScreenRound()
                 && mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_windowShowCircularMask)) {
             // Device configuration calls for a circular display mask, but we only enable the mask
@@ -9226,6 +9206,7 @@
                 transit = AppTransition.TRANSIT_UNSET;
             }
             mSkipAppTransitionAnimation = false;
+            mNoAnimationNotifyOnTransitionFinished.clear();
 
             mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
 
@@ -9395,7 +9376,13 @@
                     appAnimator.animation = null;
                 }
                 wtoken.inPendingTransaction = false;
-                setTokenVisibilityLocked(wtoken, animLp, true, transit, false, voiceInteraction);
+                if (!setTokenVisibilityLocked(
+                        wtoken, animLp, true, transit, false, voiceInteraction)){
+                    // This token isn't going to be animating. Add it to the list of tokens to
+                    // be notified of app transition complete since the notification will not be
+                    // sent be the app window animator.
+                    mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+                }
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
 
@@ -9562,6 +9549,12 @@
 
         mAppTransition.setIdle();
 
+        for (int i = mNoAnimationNotifyOnTransitionFinished.size() - 1; i >= 0; i--) {
+            final IBinder token = mNoAnimationNotifyOnTransitionFinished.get(i);
+            mAppTransition.notifyAppTransitionFinishedLocked(token);
+        }
+        mNoAnimationNotifyOnTransitionFinished.clear();
+
         if (mDeferredHideWallpaper != null) {
             hideWallpapersLocked(mDeferredHideWallpaper);
             mDeferredHideWallpaper = null;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 424e2e2..e9023fd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -146,6 +146,9 @@
 
     boolean mKeyguardGoingAwayAnimation;
 
+    /** The pixel format of the underlying SurfaceControl */
+    int mSurfaceFormat;
+
     /** This is set when there is no Surface */
     static final int NO_SURFACE = 0;
     /** This is set after the Surface has been created but before the window has been drawn. During
@@ -845,6 +848,7 @@
                     flags |= SurfaceControl.OPAQUE;
                 }
 
+                mSurfaceFormat = format;
                 if (DEBUG_SURFACE_TRACE) {
                     mSurfaceControl = new SurfaceTrace(
                             mSession.mSurfaceSession,
@@ -1610,6 +1614,28 @@
         }
     }
 
+    /**
+     * Try to change the pixel format without recreating the surface. This
+     * will be common in the case of changing from PixelFormat.OPAQUE to
+     * PixelFormat.TRANSLUCENT in the hardware-accelerated case as both
+     * requested formats resolve to the same underlying SurfaceControl format
+     * @return True if format was succesfully changed, false otherwise
+     */
+    boolean tryChangeFormatInPlaceLocked() {
+        if (mSurfaceControl == null) {
+            return false;
+        }
+        final LayoutParams attrs = mWin.getAttrs();
+        final boolean isHwAccelerated = (attrs.flags &
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+        final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+        if (format == mSurfaceFormat) {
+            setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
+            return true;
+        }
+        return false;
+    }
+
     void setOpaqueLocked(boolean isOpaque) {
         if (mSurfaceControl == null) {
             return;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 27c97d0..638783d 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -50,7 +50,7 @@
  */
 public final class UsbAlsaManager {
     private static final String TAG = UsbAlsaManager.class.getSimpleName();
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String ALSA_DIRECTORY = "/dev/snd/";
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 42eb6c3..03abfba 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.IVoiceInteractionSessionService;
 import android.service.voice.VoiceInteractionService;
@@ -177,6 +178,8 @@
 
     public boolean showLocked(Bundle args, int flags,
             IVoiceInteractionSessionShowCallback showCallback) {
+        // For now we never allow screenshots.
+        flags &= ~VoiceInteractionService.START_WITH_SCREENSHOT;
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -190,7 +193,8 @@
             mHaveAssistData = false;
             if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
-                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
+                        && isStructureEnabled()) {
                     try {
                         mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
                                 mAssistReceiver);
@@ -455,6 +459,11 @@
         }
     }
 
+    private boolean isStructureEnabled() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mToken="); pw.println(mToken);
         pw.print(prefix); pw.print("mShown="); pw.println(mShown);
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index f05a1ef..a25d327 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -151,6 +151,7 @@
     private final CharSequence mShortDescription;
     private final List<String> mSupportedUriSchemes;
     private final Icon mIcon;
+    private boolean mIsEnabled;
 
     /**
      * Helper class for creating a {@link PhoneAccount}.
@@ -165,6 +166,7 @@
         private CharSequence mShortDescription;
         private List<String> mSupportedUriSchemes = new ArrayList<String>();
         private Icon mIcon;
+        private boolean mIsEnabled = false;
 
         /**
          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
@@ -190,6 +192,7 @@
             mShortDescription = phoneAccount.getShortDescription();
             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
             mIcon = phoneAccount.getIcon();
+            mIsEnabled = phoneAccount.isEnabled();
         }
 
         /**
@@ -288,6 +291,18 @@
         }
 
         /**
+         * Sets the enabled state of the phone account.
+         *
+         * @param isEnabled The enabled state.
+         * @return The builder.
+         * @hide
+         */
+        public Builder setIsEnabled(boolean isEnabled) {
+            mIsEnabled = isEnabled;
+            return this;
+        }
+
+        /**
          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
          *
          * @return The {@link PhoneAccount}.
@@ -307,7 +322,8 @@
                     mHighlightColor,
                     mLabel,
                     mShortDescription,
-                    mSupportedUriSchemes);
+                    mSupportedUriSchemes,
+                    mIsEnabled);
         }
     }
 
@@ -320,7 +336,8 @@
             int highlightColor,
             CharSequence label,
             CharSequence shortDescription,
-            List<String> supportedUriSchemes) {
+            List<String> supportedUriSchemes,
+            boolean isEnabled) {
         mAccountHandle = account;
         mAddress = address;
         mSubscriptionAddress = subscriptionAddress;
@@ -330,6 +347,7 @@
         mLabel = label;
         mShortDescription = shortDescription;
         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
+        mIsEnabled = isEnabled;
     }
 
     public static Builder builder(
@@ -437,6 +455,15 @@
     }
 
     /**
+     * Indicates whether the user has enabled this phone account or not {@code PhoneAccounts}.
+     *
+     * @return The {@code true} if the account is enabled by the user, {@code false} otherwise.
+     */
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    /**
      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
      * scheme.
      *
@@ -466,6 +493,14 @@
         return mHighlightColor;
     }
 
+    /**
+     * Sets the enabled state of the phone account.
+     * @hide
+     */
+    public void setIsEnabled(boolean isEnabled) {
+        mIsEnabled = isEnabled;
+    }
+
     //
     // Parcelable implementation
     //
@@ -500,12 +535,14 @@
         out.writeCharSequence(mLabel);
         out.writeCharSequence(mShortDescription);
         out.writeStringList(mSupportedUriSchemes);
+
         if (mIcon == null) {
             out.writeInt(0);
         } else {
             out.writeInt(1);
             mIcon.writeToParcel(out, flags);
         }
+        out.writeByte((byte) (mIsEnabled ? 1 : 0));
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -547,11 +584,14 @@
         } else {
             mIcon = null;
         }
+        mIsEnabled = in.readByte() == 1;
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder().append("[PhoneAccount: ")
+        StringBuilder sb = new StringBuilder().append("[[")
+                .append(mIsEnabled ? 'X' : ' ')
+                .append("] PhoneAccount: ")
                 .append(mAccountHandle)
                 .append(" Capabilities: ")
                 .append(mCapabilities)
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c8ed2b0..308c204 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -377,15 +377,23 @@
     }
 
     /**
-     * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
-     * calls with a specified URI scheme.
+     * Return the {@link PhoneAccount} which will be used to place outgoing calls to addresses with
+     * the specified {@code uriScheme}. This {@link PhoneAccount} will always be a member of the
+     * list which is returned from invoking {@link #getCallCapablePhoneAccounts()}. The specific
+     * account returned depends on the following priorities:
+     * <ul>
+     * <li> If the user-selected default {@link PhoneAccount} supports the specified scheme, it will
+     * be returned.
+     * </li>
+     * <li> If there exists only one {@link PhoneAccount} that supports the specified scheme, it
+     * will be returned.
+     * </li>
+     * </ul>
      * <p>
-     * Apps must be prepared for this method to return {@code null}, indicating that there currently
-     * exists no user-chosen default {@code PhoneAccount}.
-     * <p>
+     * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
+     *
      * @param uriScheme The URI scheme.
-     * @return The {@link PhoneAccountHandle} corresponding to the user-chosen default for outgoing
-     * phone calls for a specified URI scheme.
+     * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
      */
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
@@ -403,7 +411,7 @@
      * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
      * calls. This {@code PhoneAccount} will always be a member of the list which is returned from
      * calling {@link #getCallCapablePhoneAccounts()}
-     *
+     * <p>
      * Apps must be prepared for this method to return {@code null}, indicating that there currently
      * exists no user-chosen default {@code PhoneAccount}.
      *
@@ -422,7 +430,7 @@
     }
 
     /**
-     * Sets the default account for making outgoing phone calls.
+     * Sets the user-chosen default for making outgoing phone calls.
      * @hide
      */
     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
@@ -439,6 +447,7 @@
      * Returns the current SIM call manager. Apps must be prepared for this method to return
      * {@code null}, indicating that there currently exists no user-chosen default
      * {@code PhoneAccount}.
+     *
      * @return The phone account handle of the current sim call manager.
      */
     public PhoneAccountHandle getSimCallManager() {
@@ -454,6 +463,7 @@
 
     /**
      * Sets the SIM call manager to the specified phone account.
+     *
      * @param accountHandle The phone account handle of the account to set as the sim call manager.
      * @hide
      */
@@ -469,6 +479,7 @@
 
     /**
      * Returns the list of registered SIM call managers.
+     *
      * @return List of registered SIM call managers.
      * @hide
      */
@@ -497,16 +508,6 @@
     }
 
     /**
-     * Returns the list of registered SIM call managers.
-     * @return List of registered SIM call managers.
-     * @hide
-     */
-    @SystemApi
-    public List<PhoneAccountHandle> getRegisteredConnectionManagers() {
-        return getSimCallManagers();
-    }
-
-    /**
      * Returns a list of the {@link PhoneAccountHandle}s which can be used to make and receive phone
      * calls which support the specified URI scheme.
      * <P>
@@ -534,20 +535,33 @@
 
 
     /**
-     * Return a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
-     * calls.
+     * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+     * calls. The returned list includes only those accounts which have been explicitly enabled
+     * by the user.
      *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
-     *
      */
     public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
+        return getCallCapablePhoneAccounts(false);
+    }
+
+    /**
+     * Returns a list of {@link PhoneAccountHandle}s including those which have not been enabled
+     * by the user.
+     *
+     * @return A list of {@code PhoneAccountHandle} objects.
+     * @hide
+     */
+    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getCallCapablePhoneAccounts(mContext.getOpPackageName());
+                return getTelecomService().getCallCapablePhoneAccounts(
+                        includeDisabledAccounts, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts", e);
+            Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
+                    includeDisabledAccounts + ")", e);
         }
         return new ArrayList<>();
     }
@@ -1163,6 +1177,25 @@
         }
     }
 
+    /**
+     * Enables and disables specified phone account.
+     *
+     * @param handle Handle to the phone account.
+     * @param isEnabled Enable state of the phone account.
+     * @hide
+     */
+    @SystemApi
+    public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                service.enablePhoneAccount(handle, isEnabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error enablePhoneAbbount", e);
+            }
+        }
+    }
+
     private ITelecomService getTelecomService() {
         return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
     }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index bc76f06..aa02021 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -53,7 +53,8 @@
     /**
      * @see TelecomServiceImpl#getCallCapablePhoneAccounts
      */
-    List<PhoneAccountHandle> getCallCapablePhoneAccounts(String callingPackage);
+    List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            boolean includeDisabledAccounts, String callingPackage);
 
     /**
      * @see TelecomManager#getPhoneAccountsSupportingScheme
@@ -226,4 +227,9 @@
      * @see TelecomServiceImpl#placeCall
      */
     void placeCall(in Uri handle, in Bundle extras, String callingPackage);
+
+    /**
+     * @see TelecomServiceImpl#enablePhoneAccount
+     */
+    void enablePhoneAccount(in PhoneAccountHandle accountHandle, boolean isEnabled);
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 572fdc9..771cf57 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -444,7 +444,7 @@
     @Override
     public int getDimensionPixelSize(int index, int defValue) {
         try {
-            return getDimension(index);
+            return getDimension(index, null);
         } catch (RuntimeException e) {
             String s = getString(index);
 
@@ -474,12 +474,12 @@
     @Override
     public int getLayoutDimension(int index, String name) {
         try {
-            // this will throw an exception
-            return getDimension(index);
+            // this will throw an exception if not found.
+            return getDimension(index, name);
         } catch (RuntimeException e) {
 
             if (LayoutInflater_Delegate.sIsInInclude) {
-                throw new RuntimeException();
+                throw new RuntimeException("Layout Dimension '" + name + "' not found.");
             }
 
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
@@ -494,9 +494,13 @@
         return getDimensionPixelSize(index, defValue);
     }
 
-    private int getDimension(int index) {
+    /** @param name attribute name, used for error reporting. */
+    private int getDimension(int index, @Nullable String name) {
         String s = getString(index);
         if (s == null) {
+            if (name != null) {
+                throw new RuntimeException("Attribute '" + name + "' not found");
+            }
             throw new RuntimeException();
         }
         // Check if the value is a magic constant that doesn't require a unit.
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 4072302..27b406a 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -181,7 +181,8 @@
                             // ---- END CHANGES
 
                             params = group.generateLayoutParams(attrs);
-
+                        } catch (RuntimeException ignored) {
+                            // Ignore, just fail over to child attrs.
                         } finally {
                             // ---- START CHANGES
                             sIsInInclude = false;