Merge "[AWARE] Add a group network specifier allowing matches to multiple requests" into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 4f117ee..24ab586 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4214,12 +4214,6 @@
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -6140,7 +6134,6 @@
   }
 
   public class WallpaperManager {
-    method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
     method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
     method public void clear() throws java.io.IOException;
     method public void clear(int) throws java.io.IOException;
@@ -26034,8 +26027,8 @@
     method public boolean protect(java.net.Socket);
     method public boolean protect(java.net.DatagramSocket);
     method public boolean setUnderlyingNetworks(android.net.Network[]);
-    field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
     field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+    field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
   }
 
   public class VpnService.Builder {
@@ -38884,7 +38877,7 @@
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
@@ -39601,6 +39594,7 @@
     field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -45234,15 +45228,11 @@
   public class Surface implements android.os.Parcelable {
     ctor public Surface(android.graphics.SurfaceTexture);
     method public int describeContents();
-    method public boolean isAutoRefreshEnabled();
-    method public boolean isSharedBufferModeEnabled();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
     method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
-    method public void setAutoRefreshEnabled(boolean);
-    method public void setSharedBufferModeEnabled(boolean);
     method public deprecated void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
@@ -47209,6 +47199,7 @@
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public void interrupt();
+    method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
diff --git a/api/system-current.txt b/api/system-current.txt
index e8c56f0..9963268 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4378,12 +4378,6 @@
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -6350,7 +6344,6 @@
   }
 
   public class WallpaperManager {
-    method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
     method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
     method public void clear() throws java.io.IOException;
     method public void clear(int) throws java.io.IOException;
@@ -28332,8 +28325,8 @@
     method public boolean protect(java.net.Socket);
     method public boolean protect(java.net.DatagramSocket);
     method public boolean setUnderlyingNetworks(android.net.Network[]);
-    field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
     field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+    field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
   }
 
   public class VpnService.Builder {
@@ -42129,7 +42122,7 @@
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
@@ -43040,6 +43033,7 @@
     field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -48819,15 +48813,11 @@
   public class Surface implements android.os.Parcelable {
     ctor public Surface(android.graphics.SurfaceTexture);
     method public int describeContents();
-    method public boolean isAutoRefreshEnabled();
-    method public boolean isSharedBufferModeEnabled();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
     method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
-    method public void setAutoRefreshEnabled(boolean);
-    method public void setSharedBufferModeEnabled(boolean);
     method public deprecated void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 56308b0..343228a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4227,12 +4227,6 @@
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -6161,7 +6155,6 @@
   }
 
   public class WallpaperManager {
-    method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
     method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
     method public void clear() throws java.io.IOException;
     method public void clear(int) throws java.io.IOException;
@@ -26178,8 +26171,8 @@
     method public boolean protect(java.net.Socket);
     method public boolean protect(java.net.DatagramSocket);
     method public boolean setUnderlyingNetworks(android.net.Network[]);
-    field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
     field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+    field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
   }
 
   public class VpnService.Builder {
@@ -39127,7 +39120,7 @@
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
@@ -39860,6 +39853,7 @@
     field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -45672,15 +45666,11 @@
   public class Surface implements android.os.Parcelable {
     ctor public Surface(android.graphics.SurfaceTexture);
     method public int describeContents();
-    method public boolean isAutoRefreshEnabled();
-    method public boolean isSharedBufferModeEnabled();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
     method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
-    method public void setAutoRefreshEnabled(boolean);
-    method public void setSharedBufferModeEnabled(boolean);
     method public deprecated void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
@@ -47661,6 +47651,7 @@
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public void interrupt();
+    method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
index d55190b..e36e148 100755
--- a/config/generate-preloaded-classes.sh
+++ b/config/generate-preloaded-classes.sh
@@ -17,6 +17,10 @@
   echo "Usage $0 <input classes file> <blacklist file> [extra classes files]"
   exit 1
 fi
+
+# Write file headers first
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cat "$DIR/copyright-header"
 echo "# Preloaded-classes filter file for phones.
 #
 # Classes in this file will be allocated into the boot image, and forcibly initialized in
@@ -25,9 +29,11 @@
 #
 # This file has been derived for mainline phone (and tablet) usage.
 #"
+
 input=$1
 blacklist=$2
 shift 2
 extra_classes_files=("$@")
-sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
 
+# Disable locale to enable lexicographical sorting
+LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
diff --git a/config/preloaded-classes b/config/preloaded-classes
index b6be0ee..1c842c7 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -13,8 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-#
-#
 # Preloaded-classes filter file for phones.
 #
 # Classes in this file will be allocated into the boot image, and forcibly initialized in
@@ -1454,6 +1452,7 @@
 android.icu.impl.UResource$Table
 android.icu.impl.UResource$Value
 android.icu.impl.Utility
+android.icu.impl.coll.CollationRoot
 android.icu.impl.locale.AsciiUtil
 android.icu.impl.locale.BaseLocale
 android.icu.impl.locale.BaseLocale$Cache
@@ -2276,7 +2275,6 @@
 android.util.Base64$Coder
 android.util.Base64$Decoder
 android.util.Base64$Encoder
-android.util.TimingsTraceLog
 android.util.ContainerHelpers
 android.util.DisplayMetrics
 android.util.EventLog
@@ -2328,6 +2326,7 @@
 android.util.StateSet
 android.util.SuperNotCalledException
 android.util.TimeUtils
+android.util.TimingsTraceLog
 android.util.TypedValue
 android.util.Xml
 android.util.jar.StrictJarFile
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
new file mode 100644
index 0000000..1934cbc
--- /dev/null
+++ b/config/preloaded-classes-extra
@@ -0,0 +1 @@
+android.icu.impl.coll.CollationRoot
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2166c3c..3fa8927 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -761,6 +761,7 @@
     boolean mStartedActivity;
     private boolean mDestroyed;
     private boolean mDoReportFullyDrawn = true;
+    private boolean mRestoredFromBundle;
     /** true if the activity is going through a transient pause */
     /*package*/ boolean mTemporaryPause = false;
     /** true if the activity is being destroyed in order to recreate it with a new configuration */
@@ -1006,17 +1007,13 @@
             Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
             mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                     ? mLastNonConfigurationInstances.fragments : null);
-        } else {
-            AutofillManager afm = getAutofillManager();
-            if (afm != null) {
-                afm.dismissUi();
-            }
         }
         mFragments.dispatchCreate();
         getApplication().dispatchActivityCreated(this, savedInstanceState);
         if (mVoiceInteractor != null) {
             mVoiceInteractor.attachActivity(this);
         }
+        mRestoredFromBundle = savedInstanceState != null;
         mCalled = true;
     }
 
@@ -1953,7 +1950,7 @@
         if (mDoReportFullyDrawn) {
             mDoReportFullyDrawn = false;
             try {
-                ActivityManager.getService().reportActivityFullyDrawn(mToken);
+                ActivityManager.getService().reportActivityFullyDrawn(mToken, mRestoredFromBundle);
             } catch (RemoteException e) {
             }
         }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index e5fe240..68fb7bc 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -30,8 +30,6 @@
 
 import com.android.internal.app.IVoiceInteractor;
 
-import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -90,11 +88,12 @@
             String processName, String abiOverride, int uid, Runnable crashHandler);
 
     /**
-     * Acquires a sleep token with the specified tag.
+     * Acquires a sleep token for the specified display with the specified tag.
      *
      * @param tag A string identifying the purpose of the token (eg. "Dream").
+     * @param displayId The display to apply the sleep token to.
      */
-    public abstract SleepToken acquireSleepToken(@NonNull String tag);
+    public abstract SleepToken acquireSleepToken(@NonNull String tag, int displayId);
 
     /**
      * Sleep tokens cause the activity manager to put the top activity to sleep.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 43693e1..2e4ce18 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2666,14 +2666,8 @@
         Activity activity = null;
         try {
             java.lang.ClassLoader cl = appContext.getClassLoader();
-            if (appContext.getApplicationContext() instanceof Application) {
-                activity = ((Application) appContext.getApplicationContext())
-                        .instantiateActivity(cl, component.getClassName(), r.intent);
-            }
-            if (activity == null) {
-                activity = mInstrumentation.newActivity(
-                        cl, component.getClassName(), r.intent);
-            }
+            activity = mInstrumentation.newActivity(
+                    cl, component.getClassName(), r.intent);
             StrictMode.incrementExpectedActivityCount(activity.getClass());
             r.intent.setExtrasClassLoader(cl);
             r.intent.prepareToEnterProcess();
@@ -3169,8 +3163,7 @@
             data.intent.setExtrasClassLoader(cl);
             data.intent.prepareToEnterProcess();
             data.setExtrasClassLoader(cl);
-            receiver = instantiate(cl, component, data.intent, app,
-                    Application::instantiateReceiver);
+            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
         } catch (Exception e) {
             if (DEBUG_BROADCAST) Slog.i(TAG,
                     "Finishing failed broadcast to " + data.intent.getComponent());
@@ -3258,13 +3251,12 @@
             } else {
                 try {
                     if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname);
-                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
 
                     java.lang.ClassLoader cl = packageInfo.getClassLoader();
-                    agent = instantiate(cl, classname, context,
-                            Application::instantiateBackupAgent);
+                    agent = (BackupAgent) cl.loadClass(classname).newInstance();
 
                     // set up the agent's context
+                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                     context.setOuterContext(agent);
                     agent.attach(context);
 
@@ -3324,12 +3316,9 @@
         LoadedApk packageInfo = getPackageInfoNoCheck(
                 data.info.applicationInfo, data.compatInfo);
         Service service = null;
-        Application app = null;
         try {
-            app = packageInfo.makeApplication(false, mInstrumentation);
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
-            service = instantiate(cl, data.info.name, data.intent, app,
-                    Application::instantiateService);
+            service = (Service) cl.loadClass(data.info.name).newInstance();
         } catch (Exception e) {
             if (!mInstrumentation.onException(service, e)) {
                 throw new RuntimeException(
@@ -3344,6 +3333,7 @@
             ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
             context.setOuterContext(service);
 
+            Application app = packageInfo.makeApplication(false, mInstrumentation);
             service.attach(context, this, data.info.name, data.token, app,
                     ActivityManager.getService());
             service.onCreate();
@@ -5682,8 +5672,8 @@
 
             try {
                 final ClassLoader cl = instrContext.getClassLoader();
-                mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),
-                        instrContext, Application::instantiateInstrumentation);
+                mInstrumentation = (Instrumentation)
+                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
             } catch (Exception e) {
                 throw new RuntimeException(
                     "Unable to instantiate instrumentation "
@@ -6234,8 +6224,8 @@
 
             try {
                 final java.lang.ClassLoader cl = c.getClassLoader();
-                localProvider = instantiate(cl, info.name, context,
-                        Application::instantiateProvider);
+                localProvider = (ContentProvider)cl.
+                    loadClass(info.name).newInstance();
                 provider = localProvider.getIContentProvider();
                 if (provider == null) {
                     Slog.e(TAG, "Failed to instantiate class " +
@@ -6434,49 +6424,6 @@
         }
     }
 
-    private <T> T instantiate(ClassLoader cl, String className, Context c,
-            Instantiator<T> instantiator)
-            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        Application app = getApp(c);
-        if (app != null) {
-            T a = instantiator.instantiate(app, cl, className);
-            if (a != null) return a;
-        }
-        return (T) cl.loadClass(className).newInstance();
-    }
-
-    private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
-            IntentInstantiator<T> instantiator)
-            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        Application app = getApp(c);
-        if (app != null) {
-            T a = instantiator.instantiate(app, cl, className, intent);
-            if (a != null) return a;
-        }
-        return (T) cl.loadClass(className).newInstance();
-    }
-
-    private Application getApp(Context c) {
-        // We need this shortcut to avoid actually calling getApplicationContext() on an Application
-        // because the Application may not return itself for getApplicationContext() because the
-        // API doesn't enforce it.
-        if (c instanceof Application) return (Application) c;
-        if (c.getApplicationContext() instanceof Application) {
-            return (Application) c.getApplicationContext();
-        }
-        return null;
-    }
-
-    private interface Instantiator<T> {
-        T instantiate(Application app, ClassLoader cl, String className)
-                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
-    }
-
-    private interface IntentInstantiator<T> {
-        T instantiate(Application app, ClassLoader cl, String className, Intent intent)
-                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
-    }
-
     private static class EventLoggingReporter implements EventLogger.Reporter {
         @Override
         public void report (int code, Object... list) {
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index cc23ec9..156df36 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -16,20 +16,17 @@
 
 package android.app;
 
+import java.util.ArrayList;
+
 import android.annotation.CallSuper;
-import android.app.backup.BackupAgent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
-import android.content.ContentProvider;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 
-import java.util.ArrayList;
-
 /**
  * Base class for maintaining global application state. You can provide your own
  * implementation by creating a subclass and specifying the fully-qualified name
@@ -292,73 +289,4 @@
             }
         }
     }
-
-    /**
-     * Allows application to override the creation of activities. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of receivers. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of services. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public Service instantiateService(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of providers. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public ContentProvider instantiateProvider(ClassLoader cl, String className) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of backup agents. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of instrumentation. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) {
-        return null;
-    }
 }
\ No newline at end of file
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fa9d7ca..897e42b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -376,7 +376,7 @@
     boolean convertFromTranslucent(in IBinder token);
     boolean convertToTranslucent(in IBinder token, in Bundle options);
     void notifyActivityDrawn(in IBinder token);
-    void reportActivityFullyDrawn(in IBinder token);
+    void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
     void restart();
     void performIdleMaintenance();
     void takePersistableUriPermission(in Uri uri, int modeFlags, int userId);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a218274..586f13f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1164,7 +1164,8 @@
      * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all children
      * notification in a group should be silenced (no sound or vibration) even if they are posted
      * to a {@link NotificationChannel} that has sound and/or vibration. Use this constant to
-     * mute this notification if this notification is a group child.
+     * mute this notification if this notification is a group child. This must be applied to all
+     * children notifications you want to mute.
      *
      * <p> For example, you might want to use this constant if you post a number of children
      * notifications at once (say, after a periodic sync), and only need to notify the user
@@ -1179,7 +1180,8 @@
      * to mute this notification if this notification is a group summary.
      *
      * <p>For example, you might want to use this constant if only the children notifications
-     * in your group have content and the summary is only used to visually group notifications.
+     * in your group have content and the summary is only used to visually group notifications
+     * rather than to alert the user that new information is available.
      */
     public static final int GROUP_ALERT_CHILDREN = 2;
 
@@ -2914,7 +2916,9 @@
          * Sets the group alert behavior for this notification. Use this method to mute this
          * notification if alerts for this notification's group should be handled by a different
          * notification. This is only applicable for notifications that belong to a
-         * {@link #setGroup(String) group}.
+         * {@link #setGroup(String) group}. This must be called on all notifications you want to
+         * mute. For example, if you want only the summary of your group to make noise, all
+         * children in the group should have the group alert behavior {@link #GROUP_ALERT_SUMMARY}.
          *
          * <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
          */
@@ -5182,17 +5186,22 @@
         if (extras.getBoolean(EXTRA_REDUCED_IMAGES)) {
             return;
         }
+        boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
         if (mLargeIcon != null || largeIcon != null) {
             Resources resources = context.getResources();
             Class<? extends Style> style = getNotificationStyle();
-            int maxWidth = resources.getDimensionPixelSize(R.dimen.notification_right_icon_size);
+            int maxWidth = resources.getDimensionPixelSize(isLowRam
+                    ? R.dimen.notification_right_icon_size_low_ram
+                    : R.dimen.notification_right_icon_size);
             int maxHeight = maxWidth;
             if (MediaStyle.class.equals(style)
                     || DecoratedMediaCustomViewStyle.class.equals(style)) {
-                maxHeight = resources.getDimensionPixelSize(
-                        R.dimen.notification_media_image_max_height);
-                maxWidth = resources.getDimensionPixelSize(
-                        R.dimen.notification_media_image_max_width);
+                maxHeight = resources.getDimensionPixelSize(isLowRam
+                        ? R.dimen.notification_media_image_max_height_low_ram
+                        : R.dimen.notification_media_image_max_height);
+                maxWidth = resources.getDimensionPixelSize(isLowRam
+                        ? R.dimen.notification_media_image_max_width_low_ram
+                        : R.dimen.notification_media_image_max_width);
             }
             if (mLargeIcon != null) {
                 mLargeIcon.scaleDownIfNecessary(maxWidth, maxHeight);
@@ -5201,19 +5210,22 @@
                 largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxWidth, maxHeight);
             }
         }
-        reduceImageSizesForRemoteView(contentView, context);
-        reduceImageSizesForRemoteView(headsUpContentView, context);
-        reduceImageSizesForRemoteView(bigContentView, context);
+        reduceImageSizesForRemoteView(contentView, context, isLowRam);
+        reduceImageSizesForRemoteView(headsUpContentView, context, isLowRam);
+        reduceImageSizesForRemoteView(bigContentView, context, isLowRam);
         extras.putBoolean(EXTRA_REDUCED_IMAGES, true);
     }
 
-    private void reduceImageSizesForRemoteView(RemoteViews remoteView, Context context) {
+    private void reduceImageSizesForRemoteView(RemoteViews remoteView, Context context,
+            boolean isLowRam) {
         if (remoteView != null) {
             Resources resources = context.getResources();
-            int maxWidth = resources.getDimensionPixelSize(
-                    R.dimen.notification_custom_view_max_image_width);
-            int maxHeight = resources.getDimensionPixelSize(
-                    R.dimen.notification_custom_view_max_image_height);
+            int maxWidth = resources.getDimensionPixelSize(isLowRam
+                    ? R.dimen.notification_custom_view_max_image_width_low_ram
+                    : R.dimen.notification_custom_view_max_image_width);
+            int maxHeight = resources.getDimensionPixelSize(isLowRam
+                    ? R.dimen.notification_custom_view_max_image_height_low_ram
+                    : R.dimen.notification_custom_view_max_image_height);
             remoteView.reduceImageSizes(maxWidth, maxHeight);
         }
     }
@@ -5629,16 +5641,20 @@
         public void reduceImageSizes(Context context) {
             super.reduceImageSizes(context);
             Resources resources = context.getResources();
+            boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
             if (mPicture != null) {
-                int maxPictureWidth = resources.getDimensionPixelSize(
-                        R.dimen.notification_big_picture_max_height);
-                int maxPictureHeight = resources.getDimensionPixelSize(
-                        R.dimen.notification_big_picture_max_width);
+                int maxPictureWidth = resources.getDimensionPixelSize(isLowRam
+                        ? R.dimen.notification_big_picture_max_height_low_ram
+                        : R.dimen.notification_big_picture_max_height);
+                int maxPictureHeight = resources.getDimensionPixelSize(isLowRam
+                        ? R.dimen.notification_big_picture_max_width_low_ram
+                        : R.dimen.notification_big_picture_max_width);
                 mPicture = Icon.scaleDownIfNecessary(mPicture, maxPictureWidth, maxPictureHeight);
             }
             if (mBigLargeIcon != null) {
-                int rightIconSize = resources.getDimensionPixelSize(
-                        R.dimen.notification_right_icon_size);
+                int rightIconSize = resources.getDimensionPixelSize(isLowRam
+                        ? R.dimen.notification_right_icon_size_low_ram
+                        : R.dimen.notification_right_icon_size);
                 mBigLargeIcon.scaleDownIfNecessary(rightIconSize, rightIconSize);
             }
         }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 7e8f191a..18ad9cf 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -15,24 +15,18 @@
  */
 package android.app;
 
-import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.content.Intent;
-import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
-import android.util.Slog;
 
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -115,10 +109,8 @@
         return mName;
     }
 
-    /*
+    /**
      * Returns the list of channels that belong to this group
-     *
-     * @hide
      */
     public List<NotificationChannel> getChannels() {
         return mChannels;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2a8130f..a2864b9 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -49,7 +49,7 @@
      * eg. A launcher may set its text color to black if this flag is specified.
      * @hide
      */
-    public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
+    public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
 
     /**
      * Specifies that dark theme is preferred over the current wallpaper for best presentation.
@@ -57,7 +57,13 @@
      * eg. A launcher may set its drawer color to black if this flag is specified.
      * @hide
      */
-    public static final int HINT_SUPPORTS_DARK_THEME = 0x2;
+    public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
+
+    /**
+     * Specifies that this object was generated by extracting colors from a bitmap.
+     * @hide
+     */
+    public static final int HINT_FROM_BITMAP = 1 << 2;
 
     // Maximum size that a bitmap can have to keep our calculations sane
     private static final int MAX_BITMAP_SIZE = 112;
@@ -180,13 +186,13 @@
             }
         }
 
-        int hints = calculateHints(bitmap);
+        int hints = calculateDarkHints(bitmap);
 
         if (shouldRecycle) {
             bitmap.recycle();
         }
 
-        return new WallpaperColors(primary, secondary, tertiary, hints);
+        return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints);
     }
 
     /**
@@ -348,7 +354,7 @@
      * @param source What to read.
      * @return Whether image supports dark text or not.
      */
-    private static int calculateHints(Bitmap source) {
+    private static int calculateDarkHints(Bitmap source) {
         if (source == null) {
             return 0;
         }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 16d0214..b9e7397 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -59,6 +59,7 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.service.wallpaper.WallpaperService;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -855,16 +856,6 @@
 
     /**
      * Registers a listener to get notified when the wallpaper colors change.
-     * Callback might be called from an arbitrary background thread.
-     *
-     * @param listener A listener to register
-     */
-    public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
-        addOnColorsChangedListener(listener, null);
-    }
-
-    /**
-     * Registers a listener to get notified when the wallpaper colors change
      * @param listener A listener to register
      * @param handler Where to call it from. Will be called from the main thread
      *                if null.
@@ -907,10 +898,16 @@
     }
 
     /**
-     * Get the primary colors of a wallpaper
-     * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
-     *     {@link #FLAG_LOCK}
-     * @return {@link WallpaperColors} or null if colors are unknown.
+     * Get the primary colors of a wallpaper.
+     *
+     * <p>You can expect null if:
+     * • Colors are still being processed by the system.
+     * • A live wallpaper doesn't implement {@link WallpaperService.Engine#onComputeColors()}.
+     *
+     * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     * @return Current {@link WallpaperColors} or null if colors are unknown.
+     * @see #addOnColorsChangedListener(OnColorsChangedListener, Handler)
      */
     public @Nullable WallpaperColors getWallpaperColors(int which) {
         return getWallpaperColors(which, mContext.getUserId());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 32a64b0..56123a7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3939,7 +3939,7 @@
      *         {@link android.Manifest.permission#BIND_VPN_SERVICE};</li>
      *     <li>target {@link android.os.Build.VERSION_CODES#N API 24} or above; and</li>
      *     <li><i>not</i> explicitly opt out of the feature through
-     *         {@link android.net.VpnService#METADATA_SUPPORTS_ALWAYS_ON}.</li>
+     *         {@link android.net.VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}.</li>
      * </ul>
      * The call will fail if called with the package name of an unsupported VPN app.
      *
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index dfd5996..44c2667 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -415,7 +415,8 @@
           gatt = mBluetoothManager.getBluetoothGatt();
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
-          throw new IllegalStateException("Failed to get Bluetooth");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
 
         IAdvertisingSetCallback wrapped = wrap(callback, handler);
@@ -429,7 +430,8 @@
                                      periodicData, duration, maxExtendedAdvertisingEvents, wrapped);
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to start advertising set - ", e);
-          throw new IllegalStateException("Failed to start advertising set");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
     }
 
@@ -453,8 +455,7 @@
             gatt.stopAdvertisingSet(wrapped);
        } catch (RemoteException e) {
             Log.e(TAG, "Failed to stop advertising - ", e);
-            throw new IllegalStateException("Failed to stop advertising");
-        }
+       }
     }
 
     /**
@@ -648,6 +649,16 @@
         };
     }
 
+    private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback,
+        final int error) {
+        handler.post(new Runnable() {
+              @Override
+              public void run() {
+                  callback.onAdvertisingSetStarted(null, 0, error);
+              }
+          });
+    }
+
     private void postStartFailure(final AdvertiseCallback callback, final int error) {
         mHandler.post(new Runnable() {
             @Override
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 72075a5..2aa3d09 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1508,6 +1508,11 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
     }
 
+    /** @hide */
+    public boolean isEncryptionAware() {
+        return isDirectBootAware() || isPartiallyDirectBootAware();
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9b9499c..7ae8522 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1120,12 +1120,12 @@
         final String cacheKey = getCacheKey(packageFile, flags);
         final File cacheFile = new File(mCacheDir, cacheKey);
 
-        // If the cache is not up to date, return null.
-        if (!isCacheUpToDate(packageFile, cacheFile)) {
-            return null;
-        }
-
         try {
+            // If the cache is not up to date, return null.
+            if (!isCacheUpToDate(packageFile, cacheFile)) {
+                return null;
+            }
+
             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
             Package p = fromCacheEntry(bytes);
             if (mCallback != null) {
@@ -1140,7 +1140,7 @@
                 }
             }
             return p;
-        } catch (Exception e) {
+        } catch (Throwable e) {
             Slog.w(TAG, "Error reading package cache: ", e);
 
             // If something went wrong while reading the cache entry, delete the cache file
@@ -1158,26 +1158,30 @@
             return;
         }
 
-        final String cacheKey = getCacheKey(packageFile, flags);
-        final File cacheFile = new File(mCacheDir, cacheKey);
+        try {
+            final String cacheKey = getCacheKey(packageFile, flags);
+            final File cacheFile = new File(mCacheDir, cacheKey);
 
-        if (cacheFile.exists()) {
-            if (!cacheFile.delete()) {
-                Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+            if (cacheFile.exists()) {
+                if (!cacheFile.delete()) {
+                    Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+                }
             }
-        }
 
-        final byte[] cacheEntry = toCacheEntry(parsed);
+            final byte[] cacheEntry = toCacheEntry(parsed);
 
-        if (cacheEntry == null) {
-            return;
-        }
+            if (cacheEntry == null) {
+                return;
+            }
 
-        try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
-            fos.write(cacheEntry);
-        } catch (IOException ioe) {
-            Slog.w(TAG, "Error writing cache entry.", ioe);
-            cacheFile.delete();
+            try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
+                fos.write(cacheEntry);
+            } catch (IOException ioe) {
+                Slog.w(TAG, "Error writing cache entry.", ioe);
+                cacheFile.delete();
+            }
+        } catch (Throwable e) {
+            Slog.w(TAG, "Error saving package cache.", e);
         }
     }
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 48123fe..744ee8e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -840,8 +840,8 @@
      * In order to support the always-on feature, an app has to
      * <ul>
      *     <li>target {@link VERSION_CODES#N API 24} or above, and
-     *     <li>not opt out through the {@link VpnService#METADATA_SUPPORTS_ALWAYS_ON} meta-data
-     *         field.
+     *     <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+     *         meta-data field.
      * </ul>
      *
      * @param userId The identifier of the user for whom the VPN app is installed.
diff --git a/core/java/android/net/ITetheringStatsProvider.aidl b/core/java/android/net/ITetheringStatsProvider.aidl
index 1aeabc1..da0bf4c 100644
--- a/core/java/android/net/ITetheringStatsProvider.aidl
+++ b/core/java/android/net/ITetheringStatsProvider.aidl
@@ -30,7 +30,10 @@
  */
 interface ITetheringStatsProvider {
     // Returns cumulative statistics for all tethering sessions since boot, on all upstreams.
-    NetworkStats getTetherStats();
+    // @code {how} is one of the NetworkStats.STATS_PER_* constants. If {@code how} is
+    // {@code STATS_PER_IFACE}, the provider should not include any traffic that is already
+    // counted by kernel interface counters.
+    NetworkStats getTetherStats(int how);
 
     // Sets the interface quota for the specified upstream interface. This is defined as the number
     // of bytes, starting from zero and counting from now, after which data should stop being
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 6b4f2d5..6e2654e 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.util.Pair;
 
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -185,6 +187,20 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean isIPv6() {
+        return getAddress() instanceof Inet6Address;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isIPv4() {
+        return getAddress() instanceof Inet4Address;
+    }
+
+    /**
      * Returns a string representation of this {@code IpPrefix}.
      *
      * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 62de991..bcfe938 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -76,7 +76,7 @@
      * RFC 6724 section 3.2.
      * @hide
      */
-    static int scopeForUnicastAddress(InetAddress addr) {
+    private static int scopeForUnicastAddress(InetAddress addr) {
         if (addr.isAnyLocalAddress()) {
             return RT_SCOPE_HOST;
         }
@@ -101,7 +101,7 @@
      * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
      */
     private boolean isIPv6ULA() {
-        if (address instanceof Inet6Address) {
+        if (isIPv6()) {
             byte[] bytes = address.getAddress();
             return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
         }
@@ -109,13 +109,29 @@
     }
 
     /**
+     * @return true if the address is IPv6.
+     * @hide
+     */
+    public boolean isIPv6() {
+        return address instanceof Inet6Address;
+    }
+
+    /**
+     * @return true if the address is IPv4 or is a mapped IPv4 address.
+     * @hide
+     */
+    public boolean isIPv4() {
+        return address instanceof Inet4Address;
+    }
+
+    /**
      * Utility function for the constructors.
      */
     private void init(InetAddress address, int prefixLength, int flags, int scope) {
         if (address == null ||
                 address.isMulticastAddress() ||
                 prefixLength < 0 ||
-                ((address instanceof Inet4Address) && prefixLength > 32) ||
+                (address instanceof Inet4Address && prefixLength > 32) ||
                 (prefixLength > 128)) {
             throw new IllegalArgumentException("Bad LinkAddress params " + address +
                     "/" + prefixLength);
@@ -184,6 +200,7 @@
      */
     public LinkAddress(String address, int flags, int scope) {
         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
+        // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
         init(ipAndMask.first, ipAndMask.second, flags, scope);
     }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0b92893..4bb8844 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -770,7 +770,6 @@
 
         StringJoiner joiner = new StringJoiner(", ");
 
-        // TODO: consider only enforcing that capabilities are not removed, allowing addition.
         // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
         // TODO: properly support NOT_METERED as a mutable and requestable capability.
         final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index be9e809..171adc0 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -82,6 +82,11 @@
     /** {@link #roaming} value where roaming data is accounted. */
     public static final int ROAMING_YES = 1;
 
+    /** Denotes a request for stats at the interface level. */
+    public static final int STATS_PER_IFACE = 0;
+    /** Denotes a request for stats at the interface and UID level. */
+    public static final int STATS_PER_UID = 1;
+
     // TODO: move fields to "mVariable" notation
 
     /**
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 7fb0c47..185b181 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -152,9 +152,10 @@
      * </service>
      * } </pre>
      *
-     * <p>This meta-data field defaults to {@code true} if absent.
+     * <p>This meta-data field defaults to {@code true} if absent. It will only have effect on
+     * {@link android.os.Build.VERSION_CODES#O_MR1} or higher.
      */
-    public static final String METADATA_SUPPORTS_ALWAYS_ON =
+    public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON =
             "android.net.VpnService.SUPPORTS_ALWAYS_ON";
 
     /**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index b916b43..0562716 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -220,6 +220,21 @@
     void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
 
     /**
+     * Reports that a tethering provider has reached a data limit.
+     *
+     * Currently triggers a global alert, which causes NetworkStatsService to poll counters and
+     * re-evaluate data usage.
+     *
+     * This does not take an interface name because:
+     * 1. The tethering offload stats provider cannot reliably determine the interface on which the
+     *    limit was reached, because the HAL does not provide it.
+     * 2. Firing an interface-specific alert instead of a global alert isn't really useful since in
+     *    all cases of interest, the system responds to both in the same way - it polls stats, and
+     *    then notifies NetworkPolicyManagerService of the fact.
+     */
+    void tetherLimitReached(ITetheringStatsProvider provider);
+
+    /**
      ** PPPD
      **/
 
@@ -266,7 +281,7 @@
     /**
      * Return summary of network statistics all tethering interfaces.
      */
-    NetworkStats getNetworkStatsTethering();
+    NetworkStats getNetworkStatsTethering(int how);
 
     /**
      * Set quota for an interface.
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index ca39854..50cd7b1 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -406,7 +406,7 @@
      * the local part to be at most 64 octets.
      */
     private static final String EMAIL_ADDRESS_LOCAL_PART =
-            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?";
+            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{0,62}[" + EMAIL_CHAR + "])?";
 
     /**
      * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 78cdf5d..2c1f734 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -659,6 +659,8 @@
      *
      * @see #isSharedBufferModeEnabled()
      * @see #setAutoRefreshEnabled(boolean)
+     *
+     * @hide
      */
     public void setSharedBufferModeEnabled(boolean enabled) {
         if (mIsSharedBufferModeEnabled != enabled) {
@@ -676,6 +678,8 @@
      * @return True if shared buffer mode is enabled on this surface, false otherwise
      *
      * @see #setSharedBufferModeEnabled(boolean)
+     *
+     * @hide
      */
     public boolean isSharedBufferModeEnabled() {
         return mIsSharedBufferModeEnabled;
@@ -699,6 +703,8 @@
      *
      * @see #isAutoRefreshEnabled()
      * @see #setSharedBufferModeEnabled(boolean)
+     *
+     * @hide
      */
     public void setAutoRefreshEnabled(boolean enabled) {
         if (mIsAutoRefreshEnabled != enabled) {
@@ -713,6 +719,8 @@
 
     /**
      * @return True if auto-refresh is enabled on this surface, false otherwise
+     *
+     * @hide
      */
     public boolean isAutoRefreshEnabled() {
         return mIsAutoRefreshEnabled;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2b4015f..8a9b14e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8078,10 +8078,6 @@
             boolean forAutofill, @AutofillFlags int flags) {
         if (forAutofill) {
             structure.setAutofillId(getAutofillId());
-            if (!isLaidOut()) {
-                Log.w(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring");
-                return;
-            }
             onProvideAutofillStructure(structure, flags);
             onProvideAutofillVirtualStructure(structure, flags);
         } else if (!isAssistBlocked()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index ecdfa3f..18b7334 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3400,6 +3400,13 @@
         if (childrenCount <= 0) {
             return;
         }
+
+        if (!isLaidOut()) {
+            Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
+                    + childrenCount + " children of " + getAccessibilityViewId());
+            return;
+        }
+
         structure.setChildCount(childrenCount);
         ArrayList<View> preorderedList = buildOrderedChildList();
         boolean customOrder = preorderedList == null
@@ -3476,6 +3483,13 @@
         if (structure.getChildCount() != 0) {
             return;
         }
+
+        if (!isLaidOut()) {
+            Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
+                    + mChildrenCount + " children of " + getAutofillId());
+            return;
+        }
+
         final ChildListForAutoFill children = getChildrenForAutofill(flags);
         final int childrenCount = children.size();
         structure.setChildCount(childrenCount);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index d9128d8..0b9bc57 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -23,7 +23,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.ComponentName;
 import android.content.Context;
@@ -1113,9 +1112,7 @@
      *
      * @return {@code true} if the accessibility button is supported on this device,
      * {@code false} otherwise
-     * @hide
      */
-    @SystemApi
     public static boolean isAccessibilityButtonSupported() {
         final Resources res = Resources.getSystem();
         return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a0d9099..29e5523 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1339,25 +1339,6 @@
     }
 
     /**
-     * Dismiss the Autofill UI, even if associated with other sessions.
-     *
-     * <p>Typically called when a new activity starts so it can hide the existing Save UI (if any).
-     *
-     * @hide
-     */
-    public void dismissUi() {
-        if (sVerbose) Log.v(TAG, "dismissUi()");
-
-        if (mService == null) return;
-
-        try {
-            mService.dismissUi();
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * View tracking information. Once all tracked views become invisible the session is finished.
      */
     private class TrackedViews {
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index aa8e19a..627afa7 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -49,5 +49,4 @@
     void disableOwnedAutofillServices(int userId);
     boolean isServiceSupported(int userId);
     boolean isServiceEnabled(int userId, String packageName);
-    void dismissUi();
 }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 8094bfc..dfb3642 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -524,12 +524,13 @@
         void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener);
 
         void updateDate(int year, int month, int dayOfMonth);
-        void updateDate(long date);
 
         int getYear();
         int getMonth();
         int getDayOfMonth();
-        long getDate();
+
+        void autofill(AutofillValue value);
+        AutofillValue getAutofillValue();
 
         void setFirstDayOfWeek(int firstDayOfWeek);
         int getFirstDayOfWeek();
@@ -572,6 +573,7 @@
         // The context
         protected Context mContext;
 
+        // NOTE: when subclasses change this variable, they must call resetAutofilledValue().
         protected Calendar mCurrentDate;
 
         // The current locale
@@ -582,6 +584,11 @@
         protected OnDateChangedListener mAutoFillChangeListener;
         protected ValidationCallback mValidationCallback;
 
+        // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+        // must return the exact same value that was autofilled, otherwise the widget will not be
+        // properly highlighted after autofill().
+        private long mAutofilledValue;
+
         public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
             mDelegator = delegator;
             mContext = context;
@@ -612,16 +619,38 @@
         }
 
         @Override
-        public void updateDate(long date) {
-            Calendar cal = Calendar.getInstance(mCurrentLocale);
-            cal.setTimeInMillis(date);
+        public final void autofill(AutofillValue value) {
+            if (value == null || !value.isDate()) {
+                Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+                return;
+            }
+
+            final long time = value.getDateValue();
+
+            final Calendar cal = Calendar.getInstance(mCurrentLocale);
+            cal.setTimeInMillis(time);
             updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                     cal.get(Calendar.DAY_OF_MONTH));
+
+            // Must set mAutofilledValue *after* calling subclass method to make sure the value
+            // returned by getAutofillValue() matches it.
+            mAutofilledValue = time;
         }
 
         @Override
-        public long getDate() {
-            return mCurrentDate.getTimeInMillis();
+        public final AutofillValue getAutofillValue() {
+            final long time = mAutofilledValue != 0
+                    ? mAutofilledValue
+                    : mCurrentDate.getTimeInMillis();
+            return AutofillValue.forDate(time);
+        }
+
+        /**
+         * This method must be called every time the value of the year, month, and/or day is
+         * changed by a subclass method.
+         */
+        protected void resetAutofilledValue() {
+            mAutofilledValue = 0;
         }
 
         protected void onValidationChanged(boolean valid) {
@@ -777,12 +806,7 @@
     public void autofill(AutofillValue value) {
         if (!isEnabled()) return;
 
-        if (!value.isDate()) {
-            Log.w(LOG_TAG, value + " could not be autofilled into " + this);
-            return;
-        }
-
-        mDelegate.updateDate(value.getDateValue());
+        mDelegate.autofill(value);
     }
 
     @Override
@@ -792,6 +816,6 @@
 
     @Override
     public AutofillValue getAutofillValue() {
-        return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+        return isEnabled() ? mDelegate.getAutofillValue() : null;
     }
 }
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 636519b..60b4757 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -368,12 +368,9 @@
     }
 
     @Override
-    public void init(int year, int monthOfYear, int dayOfMonth,
+    public void init(int year, int month, int dayOfMonth,
             DatePicker.OnDateChangedListener callBack) {
-        mCurrentDate.set(Calendar.YEAR, year);
-        mCurrentDate.set(Calendar.MONTH, monthOfYear);
-        mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
+        setDate(year, month, dayOfMonth);
         onDateChanged(false, false);
 
         mOnDateChangedListener = callBack;
@@ -381,11 +378,15 @@
 
     @Override
     public void updateDate(int year, int month, int dayOfMonth) {
+        setDate(year, month, dayOfMonth);
+        onDateChanged(false, true);
+    }
+
+    private void setDate(int year, int month, int dayOfMonth) {
         mCurrentDate.set(Calendar.YEAR, year);
         mCurrentDate.set(Calendar.MONTH, month);
         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
-        onDateChanged(false, true);
+        resetAutofilledValue();
     }
 
     private void onDateChanged(boolean fromUser, boolean callbackToClient) {
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 4f9316f..dba74b1 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -504,6 +504,7 @@
 
     private void setDate(int year, int month, int dayOfMonth) {
         mCurrentDate.set(year, month, dayOfMonth);
+        resetAutofilledValue();
         if (mCurrentDate.before(mMinDate)) {
             mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
         } else if (mCurrentDate.after(mMaxDate)) {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index de289bb..ae6881e 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -366,8 +366,11 @@
         void setMinute(@IntRange(from = 0, to = 59) int minute);
         int getMinute();
 
-        void setDate(long date);
-        long getDate();
+        void setDate(@IntRange(from = 0, to = 23) int hour,
+                @IntRange(from = 0, to = 59) int minute);
+
+        void autofill(AutofillValue value);
+        AutofillValue getAutofillValue();
 
         void setIs24Hour(boolean is24Hour);
         boolean is24Hour();
@@ -422,6 +425,11 @@
         protected OnTimeChangedListener mOnTimeChangedListener;
         protected OnTimeChangedListener mAutoFillChangeListener;
 
+        // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+        // must return the exact same value that was autofilled, otherwise the widget will not be
+        // properly highlighted after autofill().
+        private long mAutofilledValue;
+
         public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) {
             mDelegator = delegator;
             mContext = context;
@@ -439,19 +447,41 @@
         }
 
         @Override
-        public void setDate(long date) {
-            Calendar cal = Calendar.getInstance(mLocale);
-            cal.setTimeInMillis(date);
-            setHour(cal.get(Calendar.HOUR_OF_DAY));
-            setMinute(cal.get(Calendar.MINUTE));
+        public final void autofill(AutofillValue value) {
+            if (value == null || !value.isDate()) {
+                Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+                return;
+            }
+
+            final long time = value.getDateValue();
+
+            final Calendar cal = Calendar.getInstance(mLocale);
+            cal.setTimeInMillis(time);
+            setDate(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
+
+            // Must set mAutofilledValue *after* calling subclass method to make sure the value
+            // returned by getAutofillValue() matches it.
+            mAutofilledValue = time;
         }
 
         @Override
-        public long getDate() {
-            Calendar cal = Calendar.getInstance(mLocale);
+        public final AutofillValue getAutofillValue() {
+            if (mAutofilledValue != 0) {
+                return AutofillValue.forDate(mAutofilledValue);
+            }
+
+            final Calendar cal = Calendar.getInstance(mLocale);
             cal.set(Calendar.HOUR_OF_DAY, getHour());
             cal.set(Calendar.MINUTE, getMinute());
-            return cal.getTimeInMillis();
+            return AutofillValue.forDate(cal.getTimeInMillis());
+        }
+
+        /**
+         * This method must be called every time the value of the hour and/or minute is changed by
+         * a subclass method.
+         */
+        protected void resetAutofilledValue() {
+            mAutofilledValue = 0;
         }
 
         protected static class SavedState extends View.BaseSavedState {
@@ -532,12 +562,7 @@
     public void autofill(AutofillValue value) {
         if (!isEnabled()) return;
 
-        if (!value.isDate()) {
-            Log.w(LOG_TAG, value + " could not be autofilled into " + this);
-            return;
-        }
-
-        mDelegate.setDate(value.getDateValue());
+        mDelegate.autofill(value);
     }
 
     @Override
@@ -547,6 +572,6 @@
 
     @Override
     public AutofillValue getAutofillValue() {
-        return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+        return isEnabled() ? mDelegate.getAutofillValue() : null;
     }
 }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 526246b..706b0ce 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -506,19 +506,29 @@
         mAmPmLayout.setLayoutParams(params);
     }
 
+    @Override
+    public void setDate(int hour, int minute) {
+        setHourInternal(hour, FROM_EXTERNAL_API, true, false);
+        setMinuteInternal(minute, FROM_EXTERNAL_API, false);
+
+        onTimeChanged();
+    }
+
     /**
      * Set the current hour.
      */
     @Override
     public void setHour(int hour) {
-        setHourInternal(hour, FROM_EXTERNAL_API, true);
+        setHourInternal(hour, FROM_EXTERNAL_API, true, true);
     }
 
-    private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
+    private void setHourInternal(int hour, @ChangeSource int source, boolean announce,
+            boolean notify) {
         if (mCurrentHour == hour) {
             return;
         }
 
+        resetAutofilledValue();
         mCurrentHour = hour;
         updateHeaderHour(hour, announce);
         updateHeaderAmPm();
@@ -532,7 +542,9 @@
         }
 
         mDelegator.invalidate();
-        onTimeChanged();
+        if (notify) {
+            onTimeChanged();
+        }
     }
 
     /**
@@ -557,14 +569,15 @@
      */
     @Override
     public void setMinute(int minute) {
-        setMinuteInternal(minute, FROM_EXTERNAL_API);
+        setMinuteInternal(minute, FROM_EXTERNAL_API, true);
     }
 
-    private void setMinuteInternal(int minute, @ChangeSource int source) {
+    private void setMinuteInternal(int minute, @ChangeSource int source, boolean notify) {
         if (mCurrentMinute == minute) {
             return;
         }
 
+        resetAutofilledValue();
         mCurrentMinute = minute;
         updateHeaderMinute(minute, true);
 
@@ -576,7 +589,9 @@
         }
 
         mDelegator.invalidate();
-        onTimeChanged();
+        if (notify) {
+            onTimeChanged();
+        }
     }
 
     /**
@@ -870,7 +885,7 @@
                         valueChanged = true;
                     }
                     final boolean isTransition = mAllowAutoAdvance && autoAdvance;
-                    setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
+                    setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition, true);
                     if (isTransition) {
                         setCurrentItemShowing(MINUTE_INDEX, true, false);
 
@@ -882,7 +897,7 @@
                     if (getMinute() != newValue) {
                         valueChanged = true;
                     }
-                    setMinuteInternal(newValue, FROM_RADIAL_PICKER);
+                    setMinuteInternal(newValue, FROM_RADIAL_PICKER, true);
                     break;
             }
 
@@ -897,10 +912,10 @@
         public void onValueChanged(int pickerType, int newValue) {
             switch (pickerType) {
                 case TextInputTimePickerView.HOURS:
-                    setHourInternal(newValue, FROM_INPUT_PICKER, false);
+                    setHourInternal(newValue, FROM_INPUT_PICKER, false, true);
                     break;
                 case TextInputTimePickerView.MINUTES:
-                    setMinuteInternal(newValue, FROM_INPUT_PICKER);
+                    setMinuteInternal(newValue, FROM_INPUT_PICKER, true);
                     break;
                 case TextInputTimePickerView.AMPM:
                     setAmOrPm(newValue);
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 7a7d9a9..cc79b9c 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -284,6 +284,14 @@
     }
 
     @Override
+    public void setDate(int hour, int minute) {
+        setCurrentHour(hour, false);
+        setCurrentMinute(minute, false);
+
+        onTimeChanged();
+    }
+
+    @Override
     public void setHour(int hour) {
         setCurrentHour(hour, true);
     }
@@ -293,6 +301,7 @@
         if (currentHour == getHour()) {
             return;
         }
+        resetAutofilledValue();
         if (!is24Hour()) {
             // convert [0,23] ordinal to wall clock display
             if (currentHour >= HOURS_IN_HALF_DAY) {
@@ -328,11 +337,18 @@
 
     @Override
     public void setMinute(int minute) {
+        setCurrentMinute(minute, true);
+    }
+
+    private void setCurrentMinute(int minute, boolean notifyTimeChanged) {
         if (minute == getMinute()) {
             return;
         }
+        resetAutofilledValue();
         mMinuteSpinner.setValue(minute);
-        onTimeChanged();
+        if (notifyTimeChanged) {
+            onTimeChanged();
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index ef98a5e..c171fa6 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -80,7 +80,7 @@
         if (wallpaperManager == null) {
             Log.w(TAG, "Can't listen to color changes!");
         } else {
-            wallpaperManager.addOnColorsChangedListener(this);
+            wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
 
             // Initialize all gradients with the current colors
             Trace.beginSection("ColorExtractor#getWallpaperColors");
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index dbc086c..e6ef10b 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -111,18 +111,19 @@
 
         final List<Color> mainColors = inWallpaperColors.getMainColors();
         final int mainColorsSize = mainColors.size();
-        final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
-                WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
+        final int hints = inWallpaperColors.getColorHints();
+        final boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
+        final boolean generatedFromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0;
 
         if (mainColorsSize == 0) {
             return false;
         }
-        // Tonal is not really a sort, it takes a color from the extracted
-        // palette and finds a best fit amongst a collection of pre-defined
-        // palettes. The best fit is tweaked to be closer to the source color
-        // and replaces the original palette
 
-        // Get the most preeminent, non-blacklisted color.
+        // Decide what's the best color to use.
+        // We have 2 options:
+        // • Just pick the primary color
+        // • Filter out blacklisted colors. This is useful when palette is generated
+        //   automatically from a bitmap.
         Color bestColor = null;
         final float[] hsl = new float[3];
         for (int i = 0; i < mainColorsSize; i++) {
@@ -132,7 +133,7 @@
                     Color.blue(colorValue), hsl);
 
             // Stop when we find a color that meets our criteria
-            if (!isBlacklisted(hsl)) {
+            if (!generatedFromBitmap || !isBlacklisted(hsl)) {
                 bestColor = color;
                 break;
             }
@@ -143,6 +144,10 @@
             return false;
         }
 
+        // Tonal is not really a sort, it takes a color from the extracted
+        // palette and finds a best fit amongst a collection of pre-defined
+        // palettes. The best fit is tweaked to be closer to the source color
+        // and replaces the original palette.
         int colorValue = bestColor.toArgb();
         ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue),
                 hsl);
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index d327180..d64c9a1 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -132,10 +132,12 @@
                 context.getString(R.string.notification_channel_usb),
                 NotificationManager.IMPORTANCE_MIN));
 
-        channelsList.add(new NotificationChannel(
+        NotificationChannel foregroundChannel = new NotificationChannel(
                 FOREGROUND_SERVICE,
                 context.getString(R.string.notification_channel_foreground_service),
-                NotificationManager.IMPORTANCE_LOW));
+                NotificationManager.IMPORTANCE_LOW);
+        foregroundChannel.setBlockableSystem(true);
+        channelsList.add(foregroundChannel);
 
         nm.createNotificationChannels(channelsList);
     }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 94edde1..325f6d4 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -75,6 +75,9 @@
         case SkEncodedImageFormat::kWEBP:
             mimeType = "image/webp";
             break;
+        case SkEncodedImageFormat::kHEIF:
+            mimeType = "image/heif";
+            break;
         case SkEncodedImageFormat::kWBMP:
             mimeType = "image/vnd.wap.wbmp";
             break;
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 77fa62a..50ff50f 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -14,94 +14,91 @@
      limitations under the License.
 -->
 
+<!-- NOTE: outer layout is required to provide proper shadow. -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/autofill_save"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
-    android:layout_marginTop="32dp"
-    android:paddingTop="16dp"
-    android:elevation="32dp"
-    android:background="?android:attr/colorBackground"
     android:orientation="vertical">
 
     <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/autofill_save"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:paddingLeft="16dp"
-        android:paddingRight="16dp"
+        android:layout_marginTop="32dp"
+        android:paddingTop="16dp"
+        android:elevation="32dp"
+        android:background="?android:attr/colorBackground"
         android:orientation="vertical">
 
         <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:orientation="horizontal">
+            android:paddingLeft="16dp"
+            android:paddingRight="16dp"
+            android:orientation="vertical">
 
-            <TextView
-                android:id="@+id/autofill_save_title"
-                android:layout_width="0dp"
+            <LinearLayout
+                android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/autofill_save_title"
-                android:textSize="16sp"
-                android:textColor="?android:attr/textColorPrimary"
-                android:layout_weight="1">
-            </TextView>
+                android:orientation="horizontal">
 
-            <ImageView
-                android:id="@+id/autofill_save_close"
-                android:layout_width="wrap_content"
+                <TextView
+                    android:id="@+id/autofill_save_title"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:text="@string/autofill_save_title"
+                    android:textSize="16sp"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:layout_weight="1">
+                </TextView>
+
+            </LinearLayout>
+
+            <com.android.server.autofill.ui.CustomScrollView
+                android:id="@+id/autofill_save_custom_subtitle"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginLeft="16dp"
-                android:src="@android:drawable/ic_close"
-                android:alpha="0.54"
-                android:background="?android:attr/selectableItemBackgroundBorderless"
-                android:contentDescription="@android:string/close_button_text">
-            </ImageView>
+                android:layout_marginTop="4dp"
+                android:visibility="gone"/>
 
         </LinearLayout>
 
-        <com.android.server.autofill.ui.CustomScrollView
-            android:id="@+id/autofill_save_custom_subtitle"
-            android:layout_width="match_parent"
+        <com.android.internal.widget.ButtonBarLayout
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="4dp"
-            android:visibility="gone"/>
+            android:layout_gravity="end"
+            android:padding="16dp"
+            android:clipToPadding="false"
+            android:layout_weight="1"
+            android:orientation="horizontal">
+
+            <Space
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:visibility="invisible">
+            </Space>
+
+            <Button
+                android:id="@+id/autofill_save_no"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="?android:attr/buttonBarButtonStyle"
+                android:text="@string/autofill_save_no">
+            </Button>
+
+            <Button
+                android:id="@+id/autofill_save_yes"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="@style/Widget.Material.Button.Colored"
+                android:text="@string/autofill_save_yes">
+            </Button>
+
+        </com.android.internal.widget.ButtonBarLayout>
 
     </LinearLayout>
 
-    <com.android.internal.widget.ButtonBarLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:padding="16dp"
-        android:clipToPadding="false"
-        android:layout_weight="1"
-        android:orientation="horizontal">
-
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:visibility="invisible">
-        </Space>
-
-        <Button
-            android:id="@+id/autofill_save_no"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="?android:attr/buttonBarButtonStyle"
-            android:text="@string/autofill_save_no">
-        </Button>
-
-        <Button
-            android:id="@+id/autofill_save_yes"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@style/Widget.Material.Button.Colored"
-            android:text="@string/autofill_save_yes">
-            <requestFocus />
-        </Button>
-
-    </com.android.internal.widget.ButtonBarLayout>
-
 </LinearLayout>
diff --git a/core/res/res/values-mcc310-mnc030/strings.xml b/core/res/res/values-mcc310-mnc030/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc030/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc170 b/core/res/res/values-mcc310-mnc170
deleted file mode 120000
index cfced17..0000000
--- a/core/res/res/values-mcc310-mnc170
+++ /dev/null
@@ -1 +0,0 @@
-./values-mcc310-mnc150
\ No newline at end of file
diff --git a/core/res/res/values-mcc310-mnc170/strings.xml b/core/res/res/values-mcc310-mnc170/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc170/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc280/strings.xml b/core/res/res/values-mcc310-mnc280/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc280/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc380 b/core/res/res/values-mcc310-mnc380
deleted file mode 120000
index cfced17..0000000
--- a/core/res/res/values-mcc310-mnc380
+++ /dev/null
@@ -1 +0,0 @@
-./values-mcc310-mnc150
\ No newline at end of file
diff --git a/core/res/res/values-mcc310-mnc380/strings.xml b/core/res/res/values-mcc310-mnc380/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc380/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc410/strings.xml b/core/res/res/values-mcc310-mnc410/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc410/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc560/strings.xml b/core/res/res/values-mcc310-mnc560/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc560/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc950/strings.xml b/core/res/res/values-mcc310-mnc950/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc950/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc311-mnc180/strings.xml b/core/res/res/values-mcc311-mnc180/strings.xml
new file mode 100644
index 0000000..a3fea29
--- /dev/null
+++ b/core/res/res/values-mcc311-mnc180/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 95aa264..ca4b355 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -531,15 +531,18 @@
     <!-- Integer parameters of the wifi to cellular handover feature
          wifi should not stick to bad networks -->
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-82</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-85</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_5">12</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer>
+
     <string  translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string>
     <string  translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string>
 
@@ -626,10 +629,10 @@
     <bool name="config_automatic_brightness_available">false</bool>
 
     <!-- Fast brightness animation ramp rate in brightness units per second-->
-    <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+    <integer translatable="false" name="config_brightness_ramp_rate_fast">180</integer>
 
     <!-- Slow brightness animation ramp rate in brightness units per second-->
-    <integer translatable="false" name="config_brightness_ramp_rate_slow">40</integer>
+    <integer translatable="false" name="config_brightness_ramp_rate_slow">60</integer>
 
     <!-- Don't name config resources like this.  It should look like config_annoyDianne -->
     <bool name="config_annoy_dianne">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 12feba9..a93e6cb 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -592,6 +592,21 @@
     <!-- The size of the right icon -->
     <dimen name="notification_right_icon_size">40dp</dimen>
 
+    <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
+    <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen>
+    <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
+    <dimen name="notification_custom_view_max_image_width_low_ram">294dp</dimen>
+    <!-- The maximum height of a big picture in a notification. The images will be reduced to that height in case they are bigger. -->
+    <dimen name="notification_big_picture_max_height_low_ram">208dp</dimen>
+    <!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. -->
+    <dimen name="notification_big_picture_max_width_low_ram">294dp</dimen>
+    <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. -->
+    <dimen name="notification_media_image_max_height_low_ram">100dp</dimen>
+    <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
+    <dimen name="notification_media_image_max_width_low_ram">100dp</dimen>
+    <!-- The size of the right icon image when on low ram -->
+    <dimen name="notification_right_icon_size_low_ram">40dp</dimen>
+
     <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
     <dimen name="autofill_dataset_picker_max_size">90%</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8a5625b..ce6815f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -593,17 +593,18 @@
     <!-- This is the label for the notification channel settings that controls the behavior
         of the notification about applications that are running in the background (that is,
         perhaps confusingly, running foreground services but not the foreground UI on the screen).
-        [CHAR LIMIT=NONE] -->
-    <string name="notification_channel_foreground_service">Apps running in background</string>
+        [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6665375982962336520] -->
+    <string name="notification_channel_foreground_service">Apps consuming battery</string>
 
-    <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] -->
+    <!-- Label for foreground service notification when one app is running.
+    [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] -->
     <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
-        running in the background</string>
+        using battery</string>
 
     <!-- Label for foreground service notification when multiple apps are running.
-        [CHAR LIMIT=NONE] -->
+        [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7150914856893450380] -->
     <string name="foreground_service_apps_in_background"><xliff:g id="number">%1$d</xliff:g> apps
-        are running in the background</string>
+        are using battery</string>
 
     <!-- Content for foreground service notification when one app is running.
         [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 061413c..04cfe48 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -357,9 +357,11 @@
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_max_total_dwell_time" />
   <java-symbol type="integer" name="config_wifi_framework_associated_partial_scan_max_num_active_channels" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz" />
+  <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz" />
+  <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_link_speed_24" />
@@ -2900,7 +2902,6 @@
   <java-symbol type="id" name="autofill_save_title" />
   <java-symbol type="id" name="autofill_save_no" />
   <java-symbol type="id" name="autofill_save_yes" />
-  <java-symbol type="id" name="autofill_save_close" />
   <java-symbol type="string" name="autofill_error_cannot_autofill" />
   <java-symbol type="string" name="autofill_picker_no_suggestions" />
   <java-symbol type="plurals" name="autofill_picker_some_suggestions" />
@@ -2932,6 +2933,14 @@
   <java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
 
+  <java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
+  <java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
+  <java-symbol type="dimen" name="notification_media_image_max_width_low_ram"/>
+  <java-symbol type="dimen" name="notification_media_image_max_height_low_ram"/>
+  <java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>
+  <java-symbol type="dimen" name="notification_custom_view_max_image_height_low_ram"/>
+  <java-symbol type="dimen" name="notification_custom_view_max_image_width_low_ram"/>
+
   <!-- Accessibility fingerprint gestures -->
   <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
   <java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index 3a81c13..ae6a7f6 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -22,6 +22,8 @@
     <allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" />
     <allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
     <allow-implicit-broadcast action="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
+    <allow-implicit-broadcast action="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION" />
+    <allow-implicit-broadcast action="android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION" />
 
     <!-- Whitelist of what components are permitted as backup data transports.  The
          'service' attribute here is a flattened ComponentName string. -->
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index df2b35b..4e59baa 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -208,7 +208,6 @@
     // TODO: Currently assume full FBO damage, due to FrameInfoVisualizer::unionDirty.
     // Should should scissor/set mHasDrawn safely.
     mRenderState.scissor().setEnabled(false);
-    mHasDrawn = true;
     Glop glop;
     GlopBuilder(mRenderState, mCaches, &glop)
             .setRoundRectClipState(nullptr)
@@ -217,7 +216,11 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    // Disable blending if this is the first draw to the main framebuffer, in case app has defined
+    // transparency where it doesn't make sense - as first draw in opaque window.
+    bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
+    mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
+    mHasDrawn = true;
 }
 
 // clears and re-fills stencil with provided rendertarget space quads,
@@ -234,7 +237,7 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    mRenderState.render(glop, mRenderTarget.orthoMatrix, false);
     mRenderState.stencil().enableTest(incrementThreshold);
 }
 
@@ -346,7 +349,10 @@
 void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
         const Glop& glop) {
     prepareRender(dirtyBounds, clip);
-    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    // Disable blending if this is the first draw to the main framebuffer, in case app has defined
+    // transparency where it doesn't make sense - as first draw in opaque window.
+    bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
+    mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
     if (!mRenderTarget.frameBufferId) mHasDrawn = true;
 }
 
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 025503b..f9a1cc5 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -228,7 +228,7 @@
                 .build();
         Matrix4 ortho;
         ortho.loadOrtho(destWidth, destHeight);
-        renderState.render(glop, ortho);
+        renderState.render(glop, ortho, false);
 
         // TODO: We should convert to linear space when the target is RGBA16F
         glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index 8865c6e..b1ca4a2 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -118,7 +118,7 @@
 }
 
 void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
-    if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
+    if ((srcMode == GL_ZERO || srcMode == GL_ONE) && dstMode == GL_ZERO) {
         // disable blending
         if (mEnabled) {
             glDisable(GL_BLEND);
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index ededffb..5fc5cb2 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -262,7 +262,8 @@
 // Render
 ///////////////////////////////////////////////////////////////////////////////
 
-void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) {
+void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
+        bool overrideDisableBlending) {
     const Glop::Mesh& mesh = glop.mesh;
     const Glop::Mesh::Vertices& vertices = mesh.vertices;
     const Glop::Mesh::Indices& indices = mesh.indices;
@@ -417,7 +418,11 @@
     // ------------------------------------
     // ---------- GL state setup ----------
     // ------------------------------------
-    blend().setFactors(glop.blend.src, glop.blend.dst);
+    if (CC_UNLIKELY(overrideDisableBlending)) {
+        blend().setFactors(GL_ZERO, GL_ZERO);
+    } else {
+        blend().setFactors(glop.blend.src, glop.blend.dst);
+    }
 
     GL_CHECKPOINT(MODERATE);
 
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index df81e86..315fa2d 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -106,7 +106,7 @@
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
 
-    void render(const Glop& glop, const Matrix4& orthoMatrix);
+    void render(const Glop& glop, const Matrix4& orthoMatrix, bool overrideDisableBlending);
 
     Blend& blend() { return *mBlend; }
     MeshState& meshState() { return *mMeshState; }
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 2f48ffb..fc4d15f 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -80,8 +80,9 @@
     public static final int FILE_TYPE_BMP     = 34;
     public static final int FILE_TYPE_WBMP    = 35;
     public static final int FILE_TYPE_WEBP    = 36;
+    public static final int FILE_TYPE_HEIF    = 37;
     private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG;
-    private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WEBP;
+    private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_HEIF;
 
     // Raw image file types
     public static final int FILE_TYPE_DNG     = 300;
@@ -239,6 +240,8 @@
         addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp", MtpConstants.FORMAT_BMP, true);
         addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp", MtpConstants.FORMAT_DEFINED, false);
         addFileType("WEBP", FILE_TYPE_WEBP, "image/webp", MtpConstants.FORMAT_DEFINED, false);
+        addFileType("HEIC", FILE_TYPE_HEIF, "image/heif", MtpConstants.FORMAT_HEIF, true);
+        addFileType("HEIF", FILE_TYPE_HEIF, "image/heif", MtpConstants.FORMAT_HEIF, false);
 
         addFileType("DNG", FILE_TYPE_DNG, "image/x-adobe-dng", MtpConstants.FORMAT_DNG, true);
         addFileType("CR2", FILE_TYPE_CR2, "image/x-canon-cr2", MtpConstants.FORMAT_TIFF, false);
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index 7d078d7..88e287e 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -211,6 +211,8 @@
     public static final int FORMAT_JPX = 0x3810;
     /** Format code for DNG files */
     public static final int FORMAT_DNG = 0x3811;
+    /** Format code for HEIF files {@hide} */
+    public static final int FORMAT_HEIF = 0x3812;
     /** Format code for firmware files */
     public static final int FORMAT_UNDEFINED_FIRMWARE = 0xB802;
     /** Format code for Windows image files */
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 698c9c9..9847d705 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -595,6 +595,7 @@
             MtpConstants.FORMAT_XML_DOCUMENT,
             MtpConstants.FORMAT_FLAC,
             MtpConstants.FORMAT_DNG,
+            MtpConstants.FORMAT_HEIF,
         };
     }
 
@@ -705,6 +706,7 @@
             case MtpConstants.FORMAT_PNG:
             case MtpConstants.FORMAT_BMP:
             case MtpConstants.FORMAT_DNG:
+            case MtpConstants.FORMAT_HEIF:
                 return IMAGE_PROPERTIES;
             default:
                 return FILE_PROPERTIES;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index cf4458a..5b874cd 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -849,6 +849,7 @@
     // read EXIF data for thumbnail information
     switch (info.mFormat) {
         case MTP_FORMAT_EXIF_JPEG:
+        case MTP_FORMAT_HEIF:
         case MTP_FORMAT_JFIF: {
             ExifData *exifdata = exif_data_new_from_file(path);
             if (exifdata) {
@@ -906,6 +907,7 @@
     if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
         switch (format) {
             case MTP_FORMAT_EXIF_JPEG:
+            case MTP_FORMAT_HEIF:
             case MTP_FORMAT_JFIF: {
                 ExifData *exifdata = exif_data_new_from_file(path);
                 if (exifdata) {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
new file mode 100644
index 0000000..e7dd6c6
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
@@ -0,0 +1,501 @@
+# Copyright (C) 2017 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.
+
+
+
+type FULL
+
+### Basic QWERTY keys ###
+
+key A {
+    label:                              '\u0634'
+    base:                               '\u0634'
+    shift, capslock:                    '\u0624'
+    ctrl, alt, meta:                    none
+}
+
+key B {
+    label:                              '\u0630'
+    base:                               '\u0630'
+    shift, capslock:                    '\u200C'
+    ctrl, alt, meta:                    none
+}
+
+key C {
+    label:                              '\u0632'
+    base:                               '\u0632'
+    shift, capslock:                    '\u0698'
+    ctrl, alt, meta:                    none
+}
+
+key D {
+    label:                              '\u06CC'
+    base:                               '\u06CC'
+    shift, capslock:                    '\u064A'
+    ctrl, alt, meta:                    none
+}
+
+key E {
+    label:                              '\u062B'
+    base:                               '\u062B'
+    shift, capslock:                    '\u064D'
+    ctrl, alt, meta:                    none
+}
+
+key F {
+    label:                              '\u0628'
+    base:                               '\u0628'
+    shift, capslock:                    '\u0625'
+    ctrl, alt, meta:                    none
+}
+
+key G {
+    label:                              '\u0644'
+    base:                               '\u0644'
+    shift, capslock:                    '\u0623'
+    ctrl, alt, meta:                    none
+}
+
+key H {
+    label:                              '\u0627'
+    base:                               '\u0627'
+    shift, capslock:                    '\u0622'
+    ctrl, alt, meta:                    none
+}
+
+key I {
+    label:                              '\u0647'
+    base:                               '\u0647'
+    shift, capslock:                    '\u0651'
+    ctrl, alt, meta:                    none
+}
+
+key J {
+    label:                              '\u062A'
+    base:                               '\u062A'
+    shift, capslock:                    '\u0629'
+    ctrl, alt, meta:                    none
+}
+
+key K {
+    label:                              '\u0646'
+    base:                               '\u0646'
+    shift, capslock:                    '\u00AB'
+    ctrl, alt, meta:                    none
+}
+
+key L {
+    label:                              '\u0645'
+    base:                               '\u0645'
+    shift, capslock:                    '\u00BB'
+    ctrl, alt, meta:                    none
+}
+
+key M {
+    label:                              '\u067E'
+    base:                               '\u067E'
+    shift, capslock:                    '\u0621'
+    ctrl, alt, meta:                    none
+}
+
+key N {
+    label:                              '\u062F'
+    base:                               '\u062F'
+    shift, capslock:                    '\u0654'
+    ctrl, alt, meta:                    none
+}
+
+key O {
+    label:                              '\u062E'
+    base:                               '\u062E'
+    shift, capslock:                    ']'
+    ctrl, alt, meta:                    none
+}
+
+key P {
+    label:                              '\u062D'
+    base:                               '\u062D'
+    shift, capslock:                    '['
+    ctrl, alt, meta:                    none
+}
+
+key Q {
+    label:                              '\u0636'
+    base:                               '\u0636'
+    shift, capslock:                    '\u0652'
+    ctrl, alt, meta:                    none
+}
+
+key R {
+    label:                              '\u0642'
+    base:                               '\u0642'
+    shift, capslock:                    '\u064B'
+    ctrl, alt, meta:                    none
+}
+
+key S {
+    label:                              '\u0633'
+    base:                               '\u0633'
+    shift, capslock:                    '\u0626'
+    ctrl, alt, meta:                    none
+}
+
+key T {
+    label:                              '\u0641'
+    base:                               '\u0641'
+    shift, capslock:                    '\u064F'
+    ctrl, alt, meta:                    none
+}
+
+key U {
+    label:                              '\u0639'
+    base:                               '\u0639'
+    shift, capslock:                    '\u064E'
+    ctrl, alt, meta:                    none
+}
+
+key V {
+    label:                              '\u0631'
+    base:                               '\u0631'
+    shift, capslock:                    '\u0670'
+    ctrl, alt, meta:                    none
+}
+
+key W {
+    label:                              '\u0635'
+    base:                               '\u0635'
+    shift, capslock:                    '\u064C'
+    ctrl, alt, meta:                    none
+}
+
+key X {
+    label:                              '\u0637'
+    base:                               '\u0637'
+    shift, capslock:                    '\u0653'
+    ctrl, alt, meta:                    none
+}
+
+key Y {
+    label:                              '\u063A'
+    base:                               '\u063A'
+    shift, capslock:                    '\u0650'
+    ctrl, alt, meta:                    none
+}
+
+key Z {
+    label:                              '\u0638'
+    base:                               '\u0638'
+    shift, capslock:                    '\u0643'
+    ctrl, alt, meta:                    none
+}
+
+key 0 {
+    label, number:                      '\u06F0'
+    base:                               '\u06F0'
+    shift:                              '('
+    ctrl, alt, meta:                    none
+}
+
+key 1 {
+    label, number:                      '\u06F1'
+    base:                               '\u06F1'
+    shift:                              '!'
+    ctrl, alt, meta:                    none
+}
+
+key 2 {
+    label, number:                      '\u06F2'
+    base:                               '\u06F2'
+    shift:                              '\u066C'
+    ctrl, alt, meta:                    none
+
+}
+key 3 {
+    label, number:                      '\u06F3'
+    base:                               '\u06F3'
+    shift:                              '\u066B'
+    ctrl, alt, meta:                    none
+}
+
+key 4 {
+    label, number:                      '\u06F4'
+    base:                               '\u06F4'
+    shift:                              '\uFDFC'
+    ctrl, alt, meta:                    none
+}
+
+key 5 {
+    label, number:                      '\u06F5'
+    base:                               '\u06F5'
+    shift:                              '\u066A'
+    ctrl, alt, meta:                    none
+}
+
+key 6 {
+    label, number:                      '\u06F6'
+    base:                               '\u06F6'
+    shift:                              '\u00D7'
+    ctrl, alt, meta:                    none
+}
+
+
+key 7 {
+    label, number:                      '\u06F7'
+    base:                               '\u06F7'
+    shift:                              '\u060C'
+    ctrl, alt, meta:                    none
+}
+
+key 8 {
+    label, number:                      '\u06F8'
+    base:                               '\u06F8'
+    shift:                              '*'
+    ctrl, alt, meta:                    none
+}
+
+key 9 {
+    label, number:                      '\u06F9'
+    base:                               '\u06F9'
+    shift:                              ')'
+    ctrl, alt, meta:                    none
+}
+
+key SPACE {
+    label:                              ' '
+    base:                               ' '
+    ctrl, alt, meta:                    none
+}
+
+key ENTER {
+    label:                              '\n'
+    base:                               '\n'
+    ctrl, alt, meta:                    none
+}
+
+key TAB {
+    label:                              '\t'
+    base:                               '\t'
+    ctrl, alt, meta:                    none
+}
+
+key COMMA {
+    label, number:                      '\u0648'
+    base:                               '\u0648'
+    shift:                              '<'
+    ctrl, alt, meta:                    none
+}
+
+key PERIOD {
+    label, number:                      '.'
+    base:                               '.'
+    shift:                              '>'
+    ctrl, alt, meta:                    none
+}
+
+key SLASH {
+    label, number:                      '/'
+    base:                               '/'
+    shift:                              '\u061F'
+    ctrl, alt, meta:                    none
+}
+
+key GRAVE {
+    label, number:                      '`'
+    base:                               '`'
+    shift:                              '\u00F7'
+    ctrl, alt, meta:                    none
+}
+
+
+key MINUS {
+    label, number:                      '-'
+    base:                               '-'
+    shift:                              '_'
+    ctrl, alt, meta:                    none
+}
+
+key EQUALS {
+    label, number:                      '='
+    base:                               '='
+    shift:                              '+'
+    ctrl, alt, meta:                    none
+}
+
+key LEFT_BRACKET {
+    label, number:                      '\u062C'
+    base:                               '\u062C'
+    shift:                              '}'
+    ctrl, alt, meta:                    none
+}
+
+key RIGHT_BRACKET {
+    label, number:                      '\u0686'
+    base:                               '\u0686'
+    shift:                              '{'
+    ctrl, alt, meta:                    none
+}
+
+key BACKSLASH {
+    label, number:                      '\\'
+    base:                               '\\'
+    shift:                              '|'
+    ctrl, alt, meta:                    none
+}
+
+key SEMICOLON {
+    label, number:                      '\u06A9'
+    base:                               '\u06A9'
+    shift:                              ':'
+    ctrl, alt, meta:                    none
+}
+
+key APOSTROPHE {
+    label, number:                      '\''
+    base:                               '\''
+    shift:                              '\"'
+    ctrl, alt, meta:                    none
+}
+
+### Numeric keypad ###
+
+key NUMPAD_0 {
+    label, number:                      '0'
+    base:                               fallback INSERT
+    numlock:                            '0'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_1 {
+    label, number:                      '1'
+    base:                               fallback MOVE_END
+    numlock:                            '1'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_2 {
+    label, number:                      '2'
+    base:                               fallback DPAD_DOWN
+    numlock:                            '2'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_3 {
+    label, number:                      '3'
+    base:                               fallback PAGE_DOWN
+    numlock:                            '3'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_4 {
+    label, number:                      '4'
+    base:                               fallback DPAD_LEFT
+    numlock:                            '4'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_5 {
+    label, number:                      '5'
+    base:                               fallback DPAD_CENTER
+    numlock:                            '5'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_6 {
+    label, number:                      '6'
+    base:                               fallback DPAD_RIGHT
+    numlock:                            '6'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_7 {
+    label, number:                      '7'
+    base:                               fallback MOVE_HOME
+    numlock:                            '7'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_8 {
+    label, number:                      '8'
+    base:                               fallback DPAD_UP
+    numlock:                            '8'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_9 {
+    label, number:                      '9'
+    base:                               fallback PAGE_UP
+    numlock:                            '9'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_LEFT_PAREN {
+    label, number:                      '('
+    base:                               '('
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_RIGHT_PAREN {
+    label, number:                      ')'
+    base:                               ')'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_DIVIDE {
+    label, number:                      '/'
+    base:                               '/'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_MULTIPLY {
+    label, number:                      '*'
+    base:                               '*'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_SUBTRACT {
+    label, number:                      '-'
+    base:                               '-'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_ADD {
+    label, number:                      '+'
+    base:                               '+'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_DOT {
+    label, number:                      '.'
+    base:                               fallback FORWARD_DEL
+    numlock:                            '.'
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_COMMA {
+    label, number:                      ','
+    base:                               ','
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_EQUALS {
+    label, number:                      '='
+    base:                               '='
+    ctrl, alt, meta:                    none
+}
+
+key NUMPAD_ENTER {
+    label:                              '\n'
+    base:                               '\n' fallback ENTER
+    ctrl, alt, meta:                    none fallback ENTER
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 5644c9a..1e26226 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -119,4 +119,7 @@
 
     <!-- Latvian keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_latvian">Latvian</string>
+
+    <!-- Persian keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_persian">Persian</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index a302162..c55711a 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -151,4 +151,8 @@
     <keyboard-layout android:name="keyboard_layout_latvian"
             android:label="@string/keyboard_layout_latvian"
             android:keyboardLayout="@raw/keyboard_layout_latvian_qwerty" />
+
+    <keyboard-layout android:name="keyboard_layout_persian"
+            android:label="@string/keyboard_layout_persian"
+            android:keyboardLayout="@raw/keyboard_layout_persian" />
 </keyboard-layouts>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 24f6c13..c997160 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -108,6 +108,7 @@
     <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
 
     <!-- Keyguard -->
+    <uses-permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java
deleted file mode 100644
index 925214e..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Bundle;
-
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A PluginActivity is an activity that replaces another full activity (e.g. RecentsActivity)
- * at runtime within the sysui process.
- */
-@ProvidesInterface(version = PluginActivity.VERSION)
-public abstract class PluginActivity extends Activity implements Plugin {
-
-    public static final int VERSION = 1;
-
-    public static final String ACTION_RECENTS = "com.android.systemui.action.PLUGIN_RECENTS";
-
-    private Context mSysuiContext;
-    private boolean mSettingActionBar;
-
-    @Override
-    public final void onCreate(Context sysuiContext, Context pluginContext) {
-        mSysuiContext = sysuiContext;
-        super.attachBaseContext(pluginContext);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Theme theme = getClass().getDeclaredAnnotation(Theme.class);
-        if (theme != null && theme.value() != 0) {
-            setTheme(theme.value());
-        }
-        mSettingActionBar = true;
-        getActionBar();
-        mSettingActionBar = false;
-    }
-
-    @Override
-    public Resources getResources() {
-        return mSettingActionBar ? mSysuiContext.getResources() : super.getResources();
-    }
-
-    @Override
-    protected void attachBaseContext(Context newBase) {
-        mSysuiContext = newBase;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-    }
-
-    public Context getSysuiContext() {
-        return mSysuiContext;
-    }
-
-    public Context getPluginContext() {
-        return getBaseContext();
-    }
-
-    /**
-     * Since PluginActivities are declared as services instead of activities (since they
-     * are plugins), they can't have a theme attached to them. Instead a PluginActivity
-     * can annotate itself with @Theme to specify the resource of the style it wants
-     * to be themed with.
-     */
-    @Retention(RetentionPolicy.RUNTIME)
-    public @interface Theme {
-        int value();
-    }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
index db2e376..25ce3dd 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
@@ -21,11 +21,6 @@
     public static final int VERSION = 1;
     static DependencyProvider sProvider;
 
-    /**
-     * Allows a plugin to get a hold of static dependencies if they have declared dependence
-     * on their interface. For one-shot plugins this will only work during onCreate and will
-     * not work afterwards.
-     */
     public static <T> T get(Plugin p, Class<T> cls) {
         return sProvider.get(p, cls);
     }
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
index 8cbd94b..db508c9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
@@ -25,8 +25,7 @@
     android:id="@+id/keyguard_disable_esim"
     android:visibility="gone"
     android:text="@string/disable_carrier_button_text"
-    style="?android:attr/buttonBarButtonStyle"
+    style="@style/Keyguard.TextView"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textSize="@dimen/kg_status_line_font_size"
-    android:textColor="?android:attr/textColorSecondary"
     android:textAllCaps="@bool/kg_use_all_caps" />
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index bc29012..dde2db2 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -20,10 +20,7 @@
     android:orientation="vertical"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_marginLeft="@dimen/car_fullscreen_user_pod_margin_side"
-    android:layout_marginRight="@dimen/car_fullscreen_user_pod_margin_side"
-    android:gravity="center"
-    android:layout_weight="1" >
+    android:gravity="center" >
 
     <ImageView android:id="@+id/user_avatar"
         android:layout_gravity="center"
@@ -31,10 +28,13 @@
         android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" />
 
     <TextView android:id="@+id/user_name"
-        android:layout_width="wrap_content"
+        android:layout_width="@dimen/car_fullscreen_user_pod_width"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_above_text"
         android:textSize="@dimen/car_fullscreen_user_pod_text_size"
         android:textColor="@color/qs_user_detail_name"
+        android:ellipsize="end"
+        android:singleLine="true"
+        android:gravity="center_horizontal"
         android:layout_gravity="center_horizontal" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
index 8c55680..99d010f 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
@@ -18,7 +18,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_gravity="center">
+    android:gravity="center"
+    android:layout_gravity="center" >
 
     <!-- car_fullscreen_user_pods will be dynamically added here. -->
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index d1f7ff8..0b46b0b 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -24,4 +24,11 @@
 
     <include layout="@layout/car_status_bar_header" />
     <include layout="@layout/car_qs_footer" />
+
+    <com.android.systemui.statusbar.car.UserGridView
+        android:id="@+id/user_grid"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/car_margin"
+        android:layout_marginRight="@dimen/car_margin" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 89078f5..5f56c4e 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -18,11 +18,12 @@
 <resources>
     <dimen name="car_margin">148dp</dimen>
 
-    <dimen name="car_fullscreen_user_pod_margin_side">44dp</dimen>
     <dimen name="car_fullscreen_user_pod_margin_above_text">24dp</dimen>
+    <dimen name="car_fullscreen_user_pod_margin_between">24dp</dimen>
     <dimen name="car_fullscreen_user_pod_icon_text_size">96dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_width">192dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_height">192dp</dimen>
+    <dimen name="car_fullscreen_user_pod_width">264dp</dimen>
     <dimen name="car_fullscreen_user_pod_text_size">40sp</dimen> <!-- B1 -->
 
     <dimen name="car_navigation_button_width">64dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index ce3068d..cb5afec 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -72,6 +72,7 @@
     public KeyguardEsimArea(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mEuiccManager = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
         setOnClickListener(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ecc2111..49253ec 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -34,7 +34,6 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.PluginManagerImpl;
@@ -295,8 +294,6 @@
 
         mProviders.put(UiOffloadThread.class, UiOffloadThread::new);
 
-        mProviders.put(PluginActivityManager.class,
-                () -> new PluginActivityManager(mContext, getDependency(PluginManager.class)));
 
         mProviders.put(PowerUI.WarningsUI.class, () -> new PowerNotificationWarnings(mContext));
 
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index e3eaadd..4b37715 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -439,7 +439,12 @@
             public void onAnimationEnd(Animator animation) {
                 updateSwipeProgressFromOffset(animView, canBeDismissed);
                 mDismissPendingMap.remove(animView);
-                if (!mCancelled) {
+                boolean wasRemoved = false;
+                if (animView instanceof ExpandableNotificationRow) {
+                    ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+                    wasRemoved = row.isRemoved();
+                }
+                if (!mCancelled || wasRemoved) {
                     mCallback.onChildDismissed(animView);
                 }
                 if (endAction != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 49a076f..9adafda 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui;
 
-import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.BroadcastReceiver;
@@ -41,7 +40,6 @@
 import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.power.PowerUI;
@@ -281,10 +279,4 @@
     public SystemUI[] getServices() {
         return mServices;
     }
-
-    @Override
-    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
-        if (!mServicesStarted) return null;
-        return Dependency.get(PluginActivityManager.class).instantiate(cl, className, intent);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java
deleted file mode 100644
index 9becc38..0000000
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 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.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-
-public class PluginActivityManager {
-
-    private final Context mContext;
-    private final PluginManager mPluginManager;
-    private final ArrayMap<String, String> mActionLookup = new ArrayMap<>();
-
-    public PluginActivityManager(Context context, PluginManager pluginManager) {
-        mContext = context;
-        mPluginManager = pluginManager;
-    }
-
-    public void addActivityPlugin(String className, String action) {
-        mActionLookup.put(className, action);
-    }
-
-    public Activity instantiate(ClassLoader cl, String className, Intent intent) {
-        String action = mActionLookup.get(className);
-        if (TextUtils.isEmpty(action)) return null;
-        return mPluginManager.getOneShotPlugin(action, PluginActivity.class);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index a968399..493d244 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -42,6 +42,7 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
 import dalvik.system.PathClassLoader;
@@ -119,21 +120,14 @@
         }
         PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
                 false, mLooper, cls, this);
-        PluginListener<Plugin> listener = new PluginListener<Plugin>() {
-            @Override
-            public void onPluginConnected(Plugin plugin, Context pluginContext) { }
-        };
-        mPluginMap.put(listener, p);
         mPluginPrefs.addAction(action);
-        PluginInstanceManager.PluginInfo<T> info = p.getPlugin();
+        PluginInfo<T> info = p.getPlugin();
         if (info != null) {
             mOneShotPackages.add(info.mPackage);
             mHasOneShot = true;
             startListening();
-            mPluginMap.remove(listener);
             return info.mPlugin;
         }
-        mPluginMap.remove(listener);
         return null;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index e574c01..a48bcbd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -310,11 +310,47 @@
             vpnWarning.setMovementMethod(new LinkMovementMethod());
         }
 
+        // Note: if a new section is added, should update configSubtitleVisibility to include
+        // the handling of the subtitle
+        configSubtitleVisibility(managementMessage != null,
+                caCertsMessage != null,
+                networkLoggingMessage != null,
+                vpnMessage != null,
+                dialogView);
+
         mDialog.show();
         mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
     }
 
+    protected void configSubtitleVisibility(boolean showDeviceManagement, boolean showCaCerts,
+            boolean showNetworkLogging, boolean showVpn, View dialogView) {
+        // Device Management title should always been shown
+        // When there is a Device Management message, all subtitles should be shown
+        if (showDeviceManagement) {
+            return;
+        }
+        // Hide the subtitle if there is only 1 message shown
+        int mSectionCountExcludingDeviceMgt = 0;
+        if (showCaCerts) { mSectionCountExcludingDeviceMgt++; }
+        if (showNetworkLogging) { mSectionCountExcludingDeviceMgt++; }
+        if (showVpn) { mSectionCountExcludingDeviceMgt++; }
+
+        // No work needed if there is no sections or more than 1 section
+        if (mSectionCountExcludingDeviceMgt != 1) {
+            return;
+        }
+        if (showCaCerts) {
+            dialogView.findViewById(R.id.ca_certs_subtitle).setVisibility(View.GONE);
+        }
+        if (showNetworkLogging) {
+            dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
+        }
+        if (showVpn) {
+            dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
+        }
+    }
+
     private String getSettingsButton() {
         return mContext.getString(R.string.monitoring_button_view_policies);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
index 9730f29..d42b87b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
@@ -18,6 +18,7 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
@@ -27,6 +28,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.QSFooter;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.statusbar.car.UserGridView;
 import com.android.systemui.statusbar.phone.MultiUserSwitch;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -37,10 +39,13 @@
  */
 public class CarQSFooter extends RelativeLayout implements QSFooter,
         UserInfoController.OnUserInfoChangedListener {
+    private static final String TAG = "CarQSFooter";
+
     private UserInfoController mUserInfoController;
 
     private MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
+    private UserGridView mUserGridView;
 
     public CarQSFooter(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -54,6 +59,19 @@
 
         mUserInfoController = Dependency.get(UserInfoController.class);
 
+        mMultiUserSwitch.setOnClickListener(v -> {
+            if (mUserGridView == null) {
+                Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher.");
+                return;
+            }
+
+            if (!mUserGridView.isShowing()) {
+                mUserGridView.show();
+            } else {
+                mUserGridView.hide();
+            }
+        });
+
         findViewById(R.id.settings_button).setOnClickListener(v -> {
             ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
 
@@ -80,6 +98,10 @@
         }
     }
 
+    public void setUserGridView(UserGridView view) {
+        mUserGridView = view;
+    }
+
     @Override
     public void setListening(boolean listening) {
         if (listening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 7c2a812..13298d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -22,9 +22,12 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFooter;
+import com.android.systemui.statusbar.car.UserGridView;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 /**
  * A quick settings fragment for the car. For auto, there is no row for quick settings or ability
@@ -33,7 +36,8 @@
  */
 public class CarQSFragment extends Fragment implements QS {
     private View mHeader;
-    private QSFooter mFooter;
+    private CarQSFooter mFooter;
+    private UserGridView mUserGridView;
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -46,6 +50,12 @@
         super.onViewCreated(view, savedInstanceState);
         mHeader = view.findViewById(R.id.header);
         mFooter = view.findViewById(R.id.qs_footer);
+
+        mUserGridView = view.findViewById(R.id.user_grid);
+        mUserGridView.init(null, Dependency.get(UserSwitcherController.class),
+                false /* showInitially */);
+
+        mFooter.setUserGridView(mUserGridView);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index d10e080..4a8b43e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -43,14 +43,11 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
-import com.android.systemui.plugins.PluginActivity;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -239,8 +236,6 @@
             registerWithSystemUser();
         }
         putComponent(Recents.class, this);
-        Dependency.get(PluginActivityManager.class).addActivityPlugin(RecentsImpl.RECENTS_ACTIVITY,
-                PluginActivity.ACTION_RECENTS);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 6060134..172c62a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -53,7 +53,7 @@
         mParent = containerStub.inflate();
         mContainer = mParent.findViewById(R.id.container);
         mUserGridView = mContainer.findViewById(R.id.user_grid);
-        mUserGridView.init(statusBar, mUserSwitcherController);
+        mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */);
         mUserGridView.setUserSelectionListener(record -> {
             if (!record.isCurrent) {
                 toggleSwitchInProgress(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
index b22a2c1..e551801 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -16,19 +16,21 @@
 
 package com.android.systemui.statusbar.car;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Paint.Align;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
-import android.os.UserHandle;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -36,9 +38,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.internal.util.UserIcons;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.UserUtil;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
@@ -47,21 +47,44 @@
  * One of the uses of this is for the lock screen in auto.
  */
 public class UserGridView extends ViewPager {
+    private static final int EXPAND_ANIMATION_TIME_MS = 200;
+    private static final int HIDE_ANIMATION_TIME_MS = 133;
+
     private StatusBar mStatusBar;
     private UserSwitcherController mUserSwitcherController;
     private Adapter mAdapter;
     private UserSelectionListener mUserSelectionListener;
+    private ValueAnimator mHeightAnimator;
+    private int mTargetHeight;
+    private int mHeightChildren;
+    private boolean mShowing;
 
     public UserGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) {
+    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
+            boolean showInitially) {
         mStatusBar = statusBar;
         mUserSwitcherController = userSwitcherController;
         mAdapter = new Adapter(mUserSwitcherController);
         addOnLayoutChangeListener(mAdapter);
         setAdapter(mAdapter);
+        mShowing = showInitially;
+    }
+
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    public void show() {
+        mShowing = true;
+        animateHeightChange(getMeasuredHeight(), mHeightChildren);
+    }
+
+    public void hide() {
+        mShowing = false;
+        animateHeightChange(getMeasuredHeight(), 0);
     }
 
     public void onUserSwitched(int newUserId) {
@@ -82,16 +105,85 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
         int height = 0;
-        for(int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            child.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-            height = Math.max(child.getMeasuredHeight(), height);
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
+            height = MeasureSpec.getSize(heightMeasureSpec);
+        } else {
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                child.measure(widthMeasureSpec,
+                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+                height = Math.max(child.getMeasuredHeight(), height);
+            }
+
+            mHeightChildren = height;
+
+            // Override the height if it's not showing.
+            if (!mShowing) {
+                height = 0;
+            }
+
+            // Respect the AT_MOST request from parent.
+            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+                height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height);
+            }
         }
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
+    private void animateHeightChange(int oldHeight, int newHeight) {
+        // If there is no change in height or an animation is already in progress towards the
+        // desired height, then there's no need to make any changes.
+        if (oldHeight == newHeight || newHeight == mTargetHeight) {
+            return;
+        }
+
+        // Animation in progress is not going towards the new target, so cancel it.
+        if (mHeightAnimator != null){
+            mHeightAnimator.cancel();
+        }
+
+        mTargetHeight = newHeight;
+        mHeightAnimator = ValueAnimator.ofInt(oldHeight, mTargetHeight);
+        mHeightAnimator.addUpdateListener(valueAnimator -> {
+            ViewGroup.LayoutParams layoutParams = getLayoutParams();
+            layoutParams.height = (Integer) valueAnimator.getAnimatedValue();
+            requestLayout();
+        });
+        mHeightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animator) {}
+
+            @Override
+            public void onAnimationEnd(Animator animator) {
+                // ValueAnimator does not guarantee that the update listener will get an update
+                // to the final value, so here, the final value is set.  Though the final calculated
+                // height (mTargetHeight) could be set, WRAP_CONTENT is more appropriate.
+                ViewGroup.LayoutParams layoutParams = getLayoutParams();
+                layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+                requestLayout();
+                mHeightAnimator = null;
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animator) {}
+
+            @Override
+            public void onAnimationRepeat(Animator animator) {}
+        });
+
+        mHeightAnimator.setInterpolator(new FastOutSlowInInterpolator());
+        if (oldHeight < newHeight) {
+            // Expanding
+            mHeightAnimator.setDuration(EXPAND_ANIMATION_TIME_MS);
+        } else {
+            // Hiding
+            mHeightAnimator.setDuration(HIDE_ANIMATION_TIME_MS);
+        }
+        mHeightAnimator.start();
+    }
+
     /**
      * This is a ViewPager.PagerAdapter which deletegates the work to a
      * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have
@@ -100,7 +192,9 @@
      */
     private final class Adapter extends PagerAdapter implements View.OnLayoutChangeListener {
         private final int mPodWidth;
-        private final int mPodMargin;
+        private final int mPodMarginBetween;
+        private final int mPodImageAvatarWidth;
+        private final int mPodImageAvatarHeight;
 
         private final WrappedBaseUserAdapter mUserAdapter;
         private int mContainerWidth;
@@ -108,10 +202,15 @@
         public Adapter(UserSwitcherController controller) {
             super();
             mUserAdapter = new WrappedBaseUserAdapter(controller, this);
-            mPodWidth = getResources().getDimensionPixelSize(
+
+            Resources res = getResources();
+            mPodWidth = res.getDimensionPixelSize(R.dimen.car_fullscreen_user_pod_width);
+            mPodMarginBetween = res.getDimensionPixelSize(
+                    R.dimen.car_fullscreen_user_pod_margin_between);
+            mPodImageAvatarWidth = res.getDimensionPixelSize(
                     R.dimen.car_fullscreen_user_pod_image_avatar_width);
-            mPodMargin = getResources().getDimensionPixelSize(
-                    R.dimen.car_fullscreen_user_pod_margin_side);
+            mPodImageAvatarHeight = res.getDimensionPixelSize(
+                    R.dimen.car_fullscreen_user_pod_image_avatar_height);
         }
 
         @Override
@@ -121,9 +220,12 @@
 
         private int getIconsPerPage() {
             // We need to know how many pods we need in this page. Each pod has its own width and
-            // margins on both sides. We can then divide the measured width of the parent by the
+            // a margin between them. We can then divide the measured width of the parent by the
             // sum of pod width and margin to get the number of pods that will completely fit.
-            return mContainerWidth / (mPodWidth + mPodMargin * 2);
+            // There is one less margin than the number of pods (eg. for 5 pods, there are 4
+            // margins), so need to add the margin to the measured width to account for that.
+            return (mContainerWidth + mPodMarginBetween) /
+                    (mPodWidth + mPodMarginBetween);
         }
 
         @Override
@@ -137,7 +239,17 @@
             int iconsPerPage = getIconsPerPage();
             int limit = Math.min(mUserAdapter.getCount(), (position + 1) * iconsPerPage);
             for (int i = position * iconsPerPage; i < limit; i++) {
-                pods.addView(makeUserPod(inflater, context, i, pods));
+                View v = makeUserPod(inflater, context, i, pods);
+                pods.addView(v);
+                // This is hacky, but the dividers on the pod container LinearLayout don't seem
+                // to work for whatever reason.  Instead, set a right margin on the pod if it's not
+                // the right-most pod and there is more than one pod in the container.
+                if (i < limit - 1 && limit > 1) {
+                    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+                    params.setMargins(0, 0, mPodMarginBetween, 0);
+                    v.setLayoutParams(params);
+                }
             }
             container.addView(pods);
             return pods;
@@ -151,7 +263,8 @@
          */
         private Bitmap getDefaultUserIcon(CharSequence userName) {
             CharSequence displayText = userName.subSequence(0, 1);
-            Bitmap out = Bitmap.createBitmap(mPodWidth, mPodWidth, Bitmap.Config.ARGB_8888);
+            Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
+                    Bitmap.Config.ARGB_8888);
             Canvas canvas = new Canvas(out);
 
             // Draw the circle background.
@@ -159,7 +272,7 @@
             shape.setShape(GradientDrawable.RADIAL_GRADIENT);
             shape.setGradientRadius(1.0f);
             shape.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_bgcolor));
-            shape.setBounds(0, 0, mPodWidth, mPodWidth);
+            shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
             shape.draw(canvas);
 
             // Draw the letter in the center.
@@ -174,8 +287,8 @@
             // correct this, half the difference between the top and bottom distance metrics of the
             // font gives the offset of the font.  Bottom is a positive value, top is negative, so
             // the different is actually a sum.  The "half" operation is then factored out.
-            canvas.drawText(displayText.toString(),
-                    mPodWidth / 2, (mPodWidth - (metrics.bottom + metrics.top)) / 2, paint);
+            canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
+                    (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
 
             return out;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 844a2c4..3115361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.content.Context;
 import android.graphics.Color;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -57,4 +60,10 @@
         offsetView.getLocationOnScreen(sLocationOffset);
         return sLocationOffset[1] - sLocationBase[1];
     }
+
+    public static boolean isHapticFeedbackDisabled(Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index c45c05e..f06dd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -54,6 +54,7 @@
     private boolean mFullyPulsing;
 
     private float mAodFrontScrimOpacity = 0;
+    private Runnable mSetDozeInFrontAlphaDelayed;
 
     public DozeScrimController(ScrimController scrimController, Context context) {
         mContext = context;
@@ -69,8 +70,7 @@
             mDozingAborted = false;
             abortAnimations();
             mScrimController.setDozeBehindAlpha(1f);
-            mScrimController.setDozeInFrontAlpha(
-                    mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
+            setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
         } else {
             cancelPulsing();
             if (animate) {
@@ -83,7 +83,7 @@
             } else {
                 abortAnimations();
                 mScrimController.setDozeBehindAlpha(0f);
-                mScrimController.setDozeInFrontAlpha(0f);
+                setDozeInFrontAlpha(0f);
             }
         }
     }
@@ -97,7 +97,7 @@
         mAodFrontScrimOpacity = scrimOpacity;
         if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
                 && mDozeParameters.getAlwaysOn()) {
-            mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+            setDozeInFrontAlpha(mAodFrontScrimOpacity);
         }
     }
 
@@ -107,7 +107,7 @@
         if (!mWakeAndUnlocking) {
             mWakeAndUnlocking = true;
             mScrimController.setDozeBehindAlpha(0f);
-            mScrimController.setDozeInFrontAlpha(0f);
+            setDozeInFrontAlpha(0f);
         }
     }
 
@@ -127,7 +127,7 @@
         // be invoked when we're done so that the caller can drop the pulse wakelock.
         mPulseCallback = callback;
         mPulseReason = reason;
-        mScrimController.setDozeInFrontAlpha(1f);
+        setDozeInFrontAlpha(1f);
         mHandler.post(mPulseIn);
     }
 
@@ -138,9 +138,8 @@
         cancelPulsing();
         if (mDozing && !mWakeAndUnlocking) {
             mScrimController.setDozeBehindAlpha(1f);
-            mScrimController.setDozeInFrontAlpha(
-                    mDozeParameters.getAlwaysOn() && !mDozingAborted ?
-                            mAodFrontScrimOpacity : 1f);
+            setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() && !mDozingAborted
+                    ? mAodFrontScrimOpacity : 1f);
         }
     }
 
@@ -295,6 +294,25 @@
                 : mScrimController.getDozeBehindAlpha();
     }
 
+    private void setDozeInFrontAlpha(float opacity) {
+        setDozeInFrontAlphaDelayed(opacity, 0 /* delay */);
+
+    }
+
+    private void setDozeInFrontAlphaDelayed(float opacity, long delayMs) {
+        if (mSetDozeInFrontAlphaDelayed != null) {
+            mHandler.removeCallbacks(mSetDozeInFrontAlphaDelayed);
+            mSetDozeInFrontAlphaDelayed = null;
+        }
+        if (delayMs < 0) {
+            mScrimController.setDozeInFrontAlpha(opacity);
+        } else {
+            mHandler.postDelayed(mSetDozeInFrontAlphaDelayed = () -> {
+                setDozeInFrontAlpha(opacity);
+            }, delayMs);
+        }
+    }
+
     private final Runnable mPulseIn = new Runnable() {
         @Override
         public void run() {
@@ -364,7 +382,9 @@
             // Signal that the pulse is all finished so we can turn the screen off now.
             DozeScrimController.this.pulseFinished();
             if (mDozeParameters.getAlwaysOn()) {
-                mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+                // Setting power states can happen after we push out the frame. Make sure we
+                // stay fully opaque until the power state request reaches the lower levels.
+                setDozeInFrontAlphaDelayed(mAodFrontScrimOpacity, 30);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index c241290..5c9446ce86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -207,9 +207,9 @@
         if (mAccessibilityController == null) {
             return;
         }
-        boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
+        boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
         boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
-                && !mAccessibilityController.isAccessibilityEnabled();
+                && !clickToUnlock;
         boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index e0d9748..88a5626 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -16,14 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.support.v4.util.ArrayMap;
 import android.support.v4.util.ArraySet;
 import android.util.AttributeSet;
@@ -34,6 +39,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.stack.AnimationFilter;
 import com.android.systemui.statusbar.stack.AnimationProperties;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -623,9 +629,10 @@
                 boolean wasInShelf = icon.isInShelf();
                 boolean inShelf = iconAppearAmount == 1.0f;
                 icon.setIsInShelf(inShelf);
-                if (mVibrateOnAnimation && !justAdded && mAnimationsEnabled
-                        && wasInShelf != inShelf) {
-                    mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK));
+                if (shouldVibrateChange(wasInShelf != inShelf)) {
+                    AsyncTask.execute(
+                            () -> mVibrator.vibrate(VibrationEffect.get(
+                                    VibrationEffect.EFFECT_TICK)));
                 }
             }
             justAdded = false;
@@ -634,6 +641,25 @@
             justUndarkened = false;
         }
 
+        private boolean shouldVibrateChange(boolean inShelfChanged) {
+            if (!mVibrateOnAnimation) {
+                return false;
+            }
+            if (justAdded) {
+                return false;
+            }
+            if (!mAnimationsEnabled) {
+                return false;
+            }
+            if (!inShelfChanged) {
+                return false;
+            }
+            if (isHapticFeedbackDisabled(mContext)) {
+                return false;
+            }
+            return true;
+        }
+
         public boolean hasCustomTransformHeight() {
             return isLastExpandIcon && customTransformHeight != NO_VALUE;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index d3ee550..46f9c04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -23,9 +25,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.AsyncTask;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -45,6 +50,7 @@
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.io.FileDescriptor;
@@ -59,6 +65,7 @@
     private float mMinExpandHeight;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
+    private boolean mVibrateOnOpening;
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -203,6 +210,8 @@
         mNotificationsDragEnabled =
                 getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
         mVibrator = mContext.getSystemService(Vibrator.class);
+        mVibrateOnOpening = mContext.getResources().getBoolean(
+                R.bool.config_vibrateOnIconAnimation);
     }
 
     protected void loadDimens() {
@@ -394,7 +403,10 @@
         runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
                 false /* collapseWhenFinished */);
         notifyBarPanelExpansionChanged();
-        mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+        if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) {
+            AsyncTask.execute(
+                    () -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK)));
+        }
     }
 
     protected abstract float getOpeningHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 4fb5754..db4ea50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5261,8 +5261,7 @@
 
     private void maybePrepareWakeUpFromAod() {
         int wakefulness = mWakefulnessLifecycle.getWakefulness();
-        if (mDozing && (wakefulness == WAKEFULNESS_WAKING
-                || wakefulness == WAKEFULNESS_ASLEEP) && !isPulsing()) {
+        if (mDozing && wakefulness == WAKEFULNESS_WAKING && !isPulsing()) {
             mScrimController.prepareWakeUpFromAod();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 188f216..c2da72b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -4539,7 +4539,10 @@
                     anim.start();
                 }
             } else if (mMenuExposedView instanceof ExpandableNotificationRow) {
-                ((ExpandableNotificationRow) mMenuExposedView).resetTranslation();
+                ExpandableNotificationRow row = (ExpandableNotificationRow) mMenuExposedView;
+                if (!row.isRemoved()) {
+                    row.resetTranslation();
+                }
             }
             mMenuExposedView = null;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index bba982c..b8e9fcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -26,6 +26,8 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -34,10 +36,11 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index a8487b3..4f98836 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -29,6 +29,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableStringBuilder;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -395,6 +396,57 @@
                      mFooter.getVpnMessage(false, true, VPN_PACKAGE, null));
     }
 
+    @Test
+    public void testConfigSubtitleVisibility() {
+        View view = LayoutInflater.from(mContext)
+                .inflate(R.layout.quick_settings_footer_dialog, null);
+
+        // Device Management subtitle should be shown when there is Device Management section only
+        // Other sections visibility will be set somewhere else so it will not be tested here
+        mFooter.configSubtitleVisibility(true, false, false, false, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown
+        mFooter.configSubtitleVisibility(true, true, false, false, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown
+        mFooter.configSubtitleVisibility(true, true, true, true, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown, event if there is no
+        // Device Management section
+        mFooter.configSubtitleVisibility(false, true, true, true, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+        // If there is only 1 section, the title should be hidden
+        mFooter.configSubtitleVisibility(false, true, false, false, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        mFooter.configSubtitleVisibility(false, false, true, false, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        mFooter.configSubtitleVisibility(false, false, false, true, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+    }
+
     private CharSequence addLink(CharSequence description) {
         final SpannableStringBuilder message = new SpannableStringBuilder();
         message.append(description);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
index d1b1c5b..0a83a89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.utils.leaks;
 
+import android.content.Context;
 import android.testing.LeakCheck;
 
 import com.android.systemui.plugins.Plugin;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8d7afc2..0c787db 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -62,6 +62,14 @@
 
     // The action failed
     TYPE_FAILURE = 11;
+
+    // Type for APP_TRANSITION_REPORTED_DRAWN event: The activity was started without restoring from
+    // a bundle.
+    TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE = 12;
+
+    // Type for APP_TRANSITION_REPORTED_DRAWN event: The activity was started with restoring from
+    // a bundle.
+    TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE = 13;
   }
 
   // Types of alerts, as bit field values
@@ -4265,6 +4273,14 @@
     // FIELD: The numeric preference value (of type int) when it is changed in Settings
     FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE = 1089;
 
+    // ACTION: Logged when the app has notified that it has fully drawn. See
+    // Activity.reportFullyDrawn().
+    APP_TRANSITION_REPORTED_DRAWN = 1090;
+
+    // FIELD: The delay of the activity reporting to be fully drawn measured from the beginning of
+    // the app transition.
+    APP_TRANSITION_REPORTED_DRAWN_MS = 1091;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e854079..71f699c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -655,19 +655,6 @@
         }
 
         @Override
-        public void dismissUi() {
-            final UserHandle user = getCallingUserHandle();
-
-            synchronized (mLock) {
-                final AutofillManagerServiceImpl service = peekServiceForUserLocked(
-                        user.getIdentifier());
-                if (service != null) {
-                    service.dismissUi();
-                }
-            }
-        }
-
-        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 841b1a5..751c054 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -41,6 +41,7 @@
 import android.os.Looper;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.autofill.AutofillService;
@@ -634,12 +635,6 @@
         }
     }
 
-    void dismissUi() {
-        if (sVerbose) Slog.v(TAG, "dismissUi()");
-
-        mUi.hideAll(null);
-    }
-
     private void sendStateToClients(boolean resetClient) {
         final RemoteCallbackList<IAutoFillManagerClient> clients;
         final int userClientCount;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 2a2797c..f8c0e27 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -562,7 +562,10 @@
         void onTimeout(RemoteFillService remoteService) {
             // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
             // handled by the service, which could block.
-            remoteService.dispatchOnFillTimeout(mCancellation);
+            final ICancellationSignal cancellation = mCancellation;
+            if (cancellation != null) {
+                remoteService.dispatchOnFillTimeout(cancellation);
+            }
             remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 0351865..3727c6e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -209,9 +209,6 @@
         final View yesButton = view.findViewById(R.id.autofill_save_yes);
         yesButton.setOnClickListener((v) -> mListener.onSave());
 
-        final View closeButton = view.findViewById(R.id.autofill_save_close);
-        closeButton.setOnClickListener(cancelListener);
-
         mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
         mDialog.setContentView(view);
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index be4d106..d1cf025 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -850,6 +850,7 @@
 
     static final class InFlight {
         final PendingIntent mPendingIntent;
+        final long mWhenElapsed;
         final IBinder mListener;
         final WorkSource mWorkSource;
         final int mUid;
@@ -862,6 +863,7 @@
                 WorkSource workSource, int uid, String alarmPkg, int alarmType, String tag,
                 long nowELAPSED) {
             mPendingIntent = pendingIntent;
+            mWhenElapsed = nowELAPSED;
             mListener = listener != null ? listener.asBinder() : null;
             mWorkSource = workSource;
             mUid = uid;
@@ -883,6 +885,7 @@
         public String toString() {
             return "InFlight{"
                     + "pendingIntent=" + mPendingIntent
+                    + ", when=" + mWhenElapsed
                     + ", workSource=" + mWorkSource
                     + ", uid=" + mUid
                     + ", tag=" + mTag
@@ -1567,8 +1570,10 @@
 
             pw.println();
             pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
-            pw.print("  PendingIntent send/finish count: "); pw.println(mSendCount);
-            pw.print("  Listener send/complete count: "); pw.println(mListenerCount);
+            pw.print("  PendingIntent send count: "); pw.println(mSendCount);
+            pw.print("  PendingIntent finish count: "); pw.println(mSendFinishCount);
+            pw.print("  Listener send count: "); pw.println(mListenerCount);
+            pw.print("  Listener finish count: "); pw.println(mListenerFinishCount);
             pw.println();
 
             if (mInFlight.size() > 0) {
@@ -2949,7 +2954,11 @@
     @GuardedBy("mLock")
     private int mSendCount = 0;
     @GuardedBy("mLock")
+    private int mSendFinishCount = 0;
+    @GuardedBy("mLock")
     private int mListenerCount = 0;
+    @GuardedBy("mLock")
+    private int mListenerFinishCount = 0;
 
     class DeliveryTracker extends IAlarmCompleteListener.Stub implements PendingIntent.OnFinished {
 
@@ -3054,7 +3063,7 @@
                             Slog.i(TAG, "alarmComplete() from " + who);
                         }
                         updateTrackingLocked(inflight);
-                        mListenerCount--;
+                        mListenerFinishCount++;
                     } else {
                         // Delivery timed out, and the timeout handling already took care of
                         // updating our tracking here, so we needn't do anything further.
@@ -3075,7 +3084,7 @@
         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
                 String resultData, Bundle resultExtras) {
             synchronized (mLock) {
-                mSendCount--;
+                mSendFinishCount++;
                 updateTrackingLocked(removeLocked(pi, intent));
             }
         }
@@ -3092,7 +3101,7 @@
                         Slog.i(TAG, "Alarm listener " + who + " timed out in delivery");
                     }
                     updateTrackingLocked(inflight);
-                    mListenerCount--;
+                    mListenerFinishCount++;
                 } else {
                     if (DEBUG_LISTENER_CALLBACK) {
                         Slog.i(TAG, "Spurious timeout of listener " + who);
@@ -3125,7 +3134,7 @@
                     // 'finished' callback won't be invoked.  We also don't need
                     // to do any wakelock or stats tracking, so we have nothing
                     // left to do here but go on to the next thing.
-                    mSendCount--;
+                    mSendFinishCount++;
                     return;
                 }
             } else {
@@ -3150,6 +3159,7 @@
                     // alarm was not possible, so we have no wakelock or timeout or
                     // stats management to do.  It threw before we posted the delayed
                     // timeout message, so we're done here.
+                    mListenerFinishCount++;
                     return;
                 }
             }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ac41079..ec83a03 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4582,11 +4582,15 @@
      */
     private void updateCapabilities(
             int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
-        // Sanity check: a NetworkAgent should not change its static capabilities or parameters.
-        if (nai.everConnected) {
+        // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
+        if (nai.everConnected && !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
+                networkCapabilities)) {
+            // TODO: consider not complaining when a network agent degrade its capabilities if this
+            // does not cause any request (that is not a listen) currently matching that agent to
+            // stop being matched by the updated agent.
             String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities);
             if (!TextUtils.isEmpty(diff)) {
-                Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities:" + diff);
+                Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 3a4c9f8..a678cb3 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -34,6 +34,7 @@
 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
 import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.STATS_PER_UID;
 import static android.net.NetworkStats.TAG_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
@@ -66,6 +67,7 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.UidRange;
+import android.net.util.NetdService;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.BatteryStats;
@@ -361,7 +363,9 @@
         if (DBG) Slog.d(TAG, "Awaiting socket connection");
         connectedSignal.await();
         if (DBG) Slog.d(TAG, "Connected");
+        if (DBG) Slog.d(TAG, "Connecting native netd service");
         service.connectNativeNetdService();
+        if (DBG) Slog.d(TAG, "Connected");
         return service;
     }
 
@@ -547,6 +551,18 @@
         }
     }
 
+    @Override
+    public void tetherLimitReached(ITetheringStatsProvider provider) {
+        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        synchronized(mTetheringStatsProviders) {
+            if (!mTetheringStatsProviders.containsKey(provider)) {
+                return;
+            }
+            // No current code examines the interface parameter in a global alert. Just pass null.
+            notifyLimitReached(LIMIT_GLOBAL_ALERT, null);
+        }
+    }
+
     // Sync the state of the given chain with the native daemon.
     private void syncFirewallChainLocked(int chain, String name) {
         SparseIntArray rules;
@@ -573,14 +589,7 @@
     }
 
     private void connectNativeNetdService() {
-        boolean nativeServiceAvailable = false;
-        try {
-            mNetdService = INetd.Stub.asInterface(ServiceManager.getService(NETD_SERVICE_NAME));
-            nativeServiceAvailable = mNetdService.isAlive();
-        } catch (RemoteException e) {}
-        if (!nativeServiceAvailable) {
-            Slog.wtf(TAG, "Can't connect to NativeNetdService " + NETD_SERVICE_NAME);
-        }
+        mNetdService = NetdService.get();
     }
 
     /**
@@ -593,37 +602,31 @@
 
         // only enable bandwidth control when support exists
         final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
-        if (hasKernelSupport) {
-            Slog.d(TAG, "enabling bandwidth control");
-            try {
-                mConnector.execute("bandwidth", "enable");
-                mBandwidthControlEnabled = true;
-            } catch (NativeDaemonConnectorException e) {
-                Log.wtf(TAG, "problem enabling bandwidth controls", e);
-            }
-        } else {
-            Slog.i(TAG, "not enabling bandwidth control");
-        }
-
-        SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
-
-        if (mBandwidthControlEnabled) {
-            try {
-                getBatteryStats().noteNetworkStatsEnabled();
-            } catch (RemoteException e) {
-            }
-        }
-
-        try {
-            mConnector.execute("strict", "enable");
-            mStrictEnabled = true;
-        } catch (NativeDaemonConnectorException e) {
-            Log.wtf(TAG, "Failed strict enable", e);
-        }
 
         // push any existing quota or UID rules
         synchronized (mQuotaLock) {
 
+            if (hasKernelSupport) {
+                Slog.d(TAG, "enabling bandwidth control");
+                try {
+                    mConnector.execute("bandwidth", "enable");
+                    mBandwidthControlEnabled = true;
+                } catch (NativeDaemonConnectorException e) {
+                    Log.wtf(TAG, "problem enabling bandwidth controls", e);
+                }
+            } else {
+                Slog.i(TAG, "not enabling bandwidth control");
+            }
+
+            SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
+
+            try {
+                mConnector.execute("strict", "enable");
+                mStrictEnabled = true;
+            } catch (NativeDaemonConnectorException e) {
+                Log.wtf(TAG, "Failed strict enable", e);
+            }
+
             setDataSaverModeEnabled(mDataSaverMode);
 
             int size = mActiveQuotas.size();
@@ -701,6 +704,14 @@
                 }
             }
         }
+
+        if (mBandwidthControlEnabled) {
+            try {
+                getBatteryStats().noteNetworkStatsEnabled();
+            } catch (RemoteException e) {
+            }
+        }
+
     }
 
     /**
@@ -1779,6 +1790,30 @@
         }
     }
 
+    private void applyUidCleartextNetworkPolicy(int uid, int policy) {
+        final String policyString;
+        switch (policy) {
+            case StrictMode.NETWORK_POLICY_ACCEPT:
+                policyString = "accept";
+                break;
+            case StrictMode.NETWORK_POLICY_LOG:
+                policyString = "log";
+                break;
+            case StrictMode.NETWORK_POLICY_REJECT:
+                policyString = "reject";
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown policy " + policy);
+        }
+
+        try {
+            mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
+            mUidCleartextPolicy.put(uid, policy);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
     @Override
     public void setUidCleartextNetworkPolicy(int uid, int policy) {
         if (Binder.getCallingUid() != uid) {
@@ -1788,6 +1823,8 @@
         synchronized (mQuotaLock) {
             final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
             if (oldPolicy == policy) {
+                // This also ensures we won't needlessly apply an ACCEPT policy if we've just
+                // enabled strict and the underlying iptables rules are empty.
                 return;
             }
 
@@ -1798,28 +1835,15 @@
                 return;
             }
 
-            final String policyString;
-            switch (policy) {
-                case StrictMode.NETWORK_POLICY_ACCEPT:
-                    policyString = "accept";
-                    break;
-                case StrictMode.NETWORK_POLICY_LOG:
-                    policyString = "log";
-                    break;
-                case StrictMode.NETWORK_POLICY_REJECT:
-                    policyString = "reject";
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unknown policy " + policy);
-            }
-
-            try {
-                mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
-                mUidCleartextPolicy.put(uid, policy);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            // netd does not keep state on strict mode policies, and cannot replace a non-accept
+            // policy without deleting it first. Rather than add state to netd, just always send
+            // it an accept policy when switching between two non-accept policies.
+            if (oldPolicy != StrictMode.NETWORK_POLICY_ACCEPT &&
+                    policy != StrictMode.NETWORK_POLICY_ACCEPT) {
+                applyUidCleartextNetworkPolicy(uid, policy);
             }
         }
+        applyUidCleartextNetworkPolicy(uid, policy);
     }
 
     @Override
@@ -1840,7 +1864,13 @@
 
     private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
         @Override
-        public NetworkStats getTetherStats() {
+        public NetworkStats getTetherStats(int how) {
+            // We only need to return per-UID stats. Per-device stats are already counted by
+            // interface counters.
+            if (how != STATS_PER_UID) {
+                return new NetworkStats(SystemClock.elapsedRealtime(), 0);
+            }
+
             final NativeDaemonEvent[] events;
             try {
                 events = mConnector.executeForList("bandwidth", "gettetherstats");
@@ -1883,14 +1913,14 @@
     }
 
     @Override
-    public NetworkStats getNetworkStatsTethering() {
+    public NetworkStats getNetworkStatsTethering(int how) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
         synchronized (mTetheringStatsProviders) {
             for (ITetheringStatsProvider provider: mTetheringStatsProviders.keySet()) {
                 try {
-                    stats.combineAllValues(provider.getTetherStats());
+                    stats.combineAllValues(provider.getTetherStats(how));
                 } catch (RemoteException e) {
                     Log.e(TAG, "Problem reading tethering stats from " +
                             mTetheringStatsProviders.get(provider) + ": " + e);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1d860d6..45387bd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,6 +28,7 @@
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -1346,7 +1347,7 @@
      * Set while we are running a voice interaction.  This overrides
      * sleeping while it is active.
      */
-    private IVoiceInteractionSession mRunningVoice;
+    IVoiceInteractionSession mRunningVoice;
 
     /**
      * For some direct access we need to power manager.
@@ -1366,13 +1367,6 @@
     private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
 
     /**
-     * A list of tokens that cause the top activity to be put to sleep.
-     * They are used by components that may hide and block interaction with underlying
-     * activities.
-     */
-    final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
-
-    /**
      * Set if we are shutting down the system, similar to sleeping.
      */
     boolean mShuttingDown = false;
@@ -3237,6 +3231,18 @@
     }
 
     final void applyUpdateVrModeLocked(ActivityRecord r) {
+        // VR apps are expected to run in a main display. If an app is turning on VR for
+        // itself, but lives in a dynamic stack, then make sure that it is moved to the main
+        // fullscreen stack before enabling VR Mode.
+        // TODO: The goal of this code is to keep the VR app on the main display. When the
+        // stack implementation changes in the future, keep in mind that the use of the fullscreen
+        // stack is a means to move the activity to the main display and a moveActivityToDisplay()
+        // option would be a better choice here.
+        if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) {
+            Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId()
+                    + " to main stack for VR");
+            moveTaskToStack(r.getTask().taskId, FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */);
+        }
         mHandler.sendMessage(
                 mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
     }
@@ -4896,13 +4902,13 @@
     }
 
     @Override
-    public void reportActivityFullyDrawn(IBinder token) {
+    public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return;
             }
-            r.reportFullyDrawnLocked();
+            r.reportFullyDrawnLocked(restoredFromBundle);
         }
     }
 
@@ -12390,7 +12396,19 @@
     void onWakefulnessChanged(int wakefulness) {
         synchronized(this) {
             mWakefulness = wakefulness;
-            updateSleepIfNeededLocked();
+
+            // Also update state in a special way for running foreground services UI.
+            switch (mWakefulness) {
+                case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+                case PowerManagerInternal.WAKEFULNESS_DREAMING:
+                case PowerManagerInternal.WAKEFULNESS_DOZING:
+                    mServices.updateScreenStateLocked(false /* screenOn */);
+                    break;
+                case PowerManagerInternal.WAKEFULNESS_AWAKE:
+                default:
+                    mServices.updateScreenStateLocked(true /* screenOn */);
+                    break;
+            }
         }
     }
 
@@ -12410,14 +12428,24 @@
     }
 
     void updateSleepIfNeededLocked() {
-        final boolean shouldSleep = shouldSleepLocked();
-        if (mSleeping && !shouldSleep) {
-            mSleeping = false;
-            startTimeTrackingFocusedActivityLocked();
-            mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
-            mStackSupervisor.comeOutOfSleepIfNeededLocked();
-            sendNotifyVrManagerOfSleepState(false);
-            updateOomAdjLocked();
+        final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
+        final boolean wasSleeping = mSleeping;
+
+        if (!shouldSleep) {
+            // If wasSleeping is true, we need to wake up activity manager state from when
+            // we started sleeping. In either case, we need to apply the sleep tokens, which
+            // will wake up stacks or put them to sleep as appropriate.
+            if (wasSleeping) {
+                mSleeping = false;
+                startTimeTrackingFocusedActivityLocked();
+                mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+                mStackSupervisor.comeOutOfSleepIfNeededLocked();
+            }
+            mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */);
+            if (wasSleeping) {
+                sendNotifyVrManagerOfSleepState(false);
+                updateOomAdjLocked();
+            }
         } else if (!mSleeping && shouldSleep) {
             mSleeping = true;
             if (mCurAppTimeTracker != null) {
@@ -12428,40 +12456,6 @@
             sendNotifyVrManagerOfSleepState(true);
             updateOomAdjLocked();
         }
-
-        // Also update state in a special way for running foreground services UI.
-        switch (mWakefulness) {
-            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
-            case PowerManagerInternal.WAKEFULNESS_DREAMING:
-            case PowerManagerInternal.WAKEFULNESS_DOZING:
-                mServices.updateScreenStateLocked(false);
-                break;
-            case PowerManagerInternal.WAKEFULNESS_AWAKE:
-            default:
-                mServices.updateScreenStateLocked(true);
-                break;
-        }
-    }
-
-    private boolean shouldSleepLocked() {
-        // Resume applications while running a voice interactor.
-        if (mRunningVoice != null) {
-            return false;
-        }
-
-        // TODO: Transform the lock screen state into a sleep token instead.
-        switch (mWakefulness) {
-            case PowerManagerInternal.WAKEFULNESS_AWAKE:
-            case PowerManagerInternal.WAKEFULNESS_DREAMING:
-                // Pause applications whenever the lock screen is shown or any sleep
-                // tokens have been acquired.
-                return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
-            case PowerManagerInternal.WAKEFULNESS_DOZING:
-            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
-            default:
-                // If we're asleep then pause applications unconditionally.
-                return true;
-        }
     }
 
     /** Pokes the task persister. */
@@ -12502,6 +12496,7 @@
 
         synchronized(this) {
             mShuttingDown = true;
+            mStackSupervisor.prepareForShutdownLocked();
             updateEventDispatchingLocked();
             timedout = mStackSupervisor.shutdownLocked(timeout);
         }
@@ -14916,6 +14911,14 @@
                 this, in, out, err, args, callback, resultReceiver);
     }
 
+    SleepToken acquireSleepToken(String tag, int displayId) {
+        synchronized (this) {
+            final SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId);
+            updateSleepIfNeededLocked();
+            return token;
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -15812,7 +15815,7 @@
         if (dumpPackage == null) {
             pw.println("  mWakefulness="
                     + PowerManagerInternal.wakefulnessToString(mWakefulness));
-            pw.println("  mSleepTokens=" + mSleepTokens);
+            pw.println("  mSleepTokens=" + mStackSupervisor.mSleepTokens);
             pw.println("  mSleeping=" + mSleeping);
             pw.println("  mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
             if (mRunningVoice != null) {
@@ -23772,15 +23775,9 @@
         }
 
         @Override
-        public SleepToken acquireSleepToken(String tag) {
+        public SleepToken acquireSleepToken(String tag, int displayId) {
             Preconditions.checkNotNull(tag);
-
-            synchronized (ActivityManagerService.this) {
-                SleepTokenImpl token = new SleepTokenImpl(tag);
-                mSleepTokens.add(token);
-                updateSleepIfNeededLocked();
-                return token;
-            }
+            return ActivityManagerService.this.acquireSleepToken(tag, displayId);
         }
 
         @Override
@@ -24217,30 +24214,6 @@
         }
     }
 
-    private final class SleepTokenImpl extends SleepToken {
-        private final String mTag;
-        private final long mAcquireTime;
-
-        public SleepTokenImpl(String tag) {
-            mTag = tag;
-            mAcquireTime = SystemClock.uptimeMillis();
-        }
-
-        @Override
-        public void release() {
-            synchronized (ActivityManagerService.this) {
-                if (mSleepTokens.remove(this)) {
-                    updateSleepIfNeededLocked();
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "{\"" + mTag + "\", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
-        }
-    }
-
     /**
      * An implementation of IAppTask, that allows an app to manage its own tasks via
      * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 98815d7..f396e9e 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -15,12 +15,17 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -67,12 +72,14 @@
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     private long mCurrentTransitionStartTime = INVALID_START_TIME;
+    private long mLastTransitionStartTime = INVALID_START_TIME;
 
     private int mCurrentTransitionDeviceUptime;
     private int mCurrentTransitionDelayMs;
     private boolean mLoggedTransitionStarting;
 
     private final SparseArray<StackTransitionInfo> mStackTransitionInfo = new SparseArray<>();
+    private final SparseArray<StackTransitionInfo> mLastStackTransitionInfo = new SparseArray<>();
 
     private final class StackTransitionInfo {
         private ActivityRecord launchedActivity;
@@ -136,6 +143,7 @@
     void notifyActivityLaunching() {
         if (!isAnyTransitionActive()) {
             mCurrentTransitionStartTime = SystemClock.uptimeMillis();
+            mLastTransitionStartTime = mCurrentTransitionStartTime;
         }
     }
 
@@ -223,7 +231,8 @@
         newInfo.launchedActivity = launchedActivity;
         newInfo.currentTransitionProcessRunning = processRunning;
         newInfo.startResult = resultCode;
-        mStackTransitionInfo.append(stackId, newInfo);
+        mStackTransitionInfo.put(stackId, newInfo);
+        mLastStackTransitionInfo.put(stackId, newInfo);
         mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
     }
 
@@ -361,7 +370,7 @@
             builder.setType(type);
             builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
             final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp();
-            if (isInstantApp && info.launchedActivity.launchedFromPackage != null) {
+            if (info.launchedActivity.launchedFromPackage != null) {
                 builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
                         info.launchedActivity.launchedFromPackage);
             }
@@ -388,6 +397,24 @@
         }
     }
 
+    void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
+        final StackTransitionInfo info = mLastStackTransitionInfo.get(r.getStackId());
+        if (info == null) {
+            return;
+        }
+        final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
+        builder.setPackageName(r.packageName);
+        builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
+        builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS,
+                SystemClock.uptimeMillis() - mLastTransitionStartTime);
+        builder.setType(restoredFromBundle
+                ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
+                : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
+        builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
+                info.currentTransitionProcessRunning ? 1 : 0);
+        mMetricsLogger.write(builder);
+    }
+
     private int getTransitionType(StackTransitionInfo info) {
         if (info.currentTransitionProcessRunning) {
             if (info.startResult == START_SUCCESS) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8cab918..44727c3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -146,6 +146,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Log;
@@ -947,8 +948,6 @@
         // the user leaves that mode.
         mLastReportedMultiWindowMode = !task.mFullscreen;
         mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID);
-
-        onOverrideConfigurationSent();
     }
 
     void removeWindowContainer() {
@@ -1341,7 +1340,9 @@
                 intent, getUriPermissionsLocked(), userId);
         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
         boolean unsent = true;
-        final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity();
+        final ActivityStack stack = getStack();
+        final boolean isTopActivityWhileSleeping = isTopRunningActivity()
+                && (stack != null ? stack.shouldSleepActivities() : service.isSleepingLocked());
 
         // We want to immediately deliver the intent to the activity if:
         // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
@@ -1731,7 +1732,7 @@
             // If the screen is going to turn on because the caller explicitly requested it and
             // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
             // pause and then resume again later, which will result in a double life-cycle event.
-            mStackSupervisor.checkReadyForSleepLocked();
+            stack.checkReadyForSleep();
         }
     }
 
@@ -1835,7 +1836,7 @@
         }
     }
 
-    public void reportFullyDrawnLocked() {
+    public void reportFullyDrawnLocked(boolean restoredFromBundle) {
         final long curTime = SystemClock.uptimeMillis();
         if (displayStartTime != 0) {
             reportLaunchTimeLocked(curTime);
@@ -1868,6 +1869,8 @@
             }
             stack.mFullyDrawnStartTime = 0;
         }
+        mStackSupervisor.mActivityMetricsLogger.logAppTransitionReportedDrawn(this,
+                restoredFromBundle);
         fullyDrawnStartTime = 0;
     }
 
@@ -2011,6 +2014,13 @@
 
     /** Checks whether the activity should be shown for current user. */
     public boolean okToShowLocked() {
+        // We cannot show activities when the device is locked and the application is not
+        // encryption aware.
+        if (!StorageManager.isUserKeyUnlocked(userId)
+                && !info.applicationInfo.isEncryptionAware()) {
+            return false;
+        }
+
         return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
                 || (mStackSupervisor.isCurrentProfileLocked(userId)
                 && service.mUserController.isUserRunningLocked(userId, 0 /* flags */));
@@ -2210,15 +2220,12 @@
      * a new merged configuration is sent to the client for this activity.
      */
     void setLastReportedConfiguration(@NonNull MergedConfiguration config) {
-        mLastReportedConfiguration.setTo(config);
+        setLastReportedConfiguration(config.getGlobalConfiguration(),
+            config.getOverrideConfiguration());
     }
 
-    /** Call when override config was sent to the Window Manager to update internal records. */
-    // TODO(b/36505427): Why do we set last reported based on sending the config to WM? Seems like
-    // we should only set this when we actually report to the activity which is what the method
-    // setLastReportedMergedOverrideConfiguration() does. Investigate if this is really needed.
-    void onOverrideConfigurationSent() {
-        mLastReportedConfiguration.setOverrideConfiguration(getMergedOverrideConfiguration());
+    void setLastReportedConfiguration(Configuration global, Configuration override) {
+        mLastReportedConfiguration.setConfiguration(global, override);
     }
 
     @Override
@@ -2232,9 +2239,6 @@
             return;
         }
         mWindowContainerController.onOverrideConfigurationChanged(newConfig, mBounds);
-        // TODO(b/36505427): Can we consolidate the call points of onOverrideConfigurationSent()
-        // to just use this method instead?
-        onOverrideConfigurationSent();
     }
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
@@ -2421,8 +2425,8 @@
 
         // Update last reported values.
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
-        mLastReportedConfiguration.setConfiguration(service.getGlobalConfiguration(),
-                newMergedOverrideConfig);
+
+        setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
 
         if (changes == 0 && !forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 896f846..84fd0de 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1170,10 +1170,25 @@
         }
     }
 
+    void checkReadyForSleep() {
+        if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
+            mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
+        }
+    }
+
     /**
+     * Tries to put the activities in the stack to sleep.
+     *
+     * If the stack is not in a state where its activities can be put to sleep, this function will
+     * start any necessary actions to move the stack into such a state. It is expected that this
+     * function get called again when those actions complete.
+     *
+     * @param shuttingDown true when the called because the device is shutting down.
      * @return true if something must be done before going to sleep.
      */
-    boolean checkReadyForSleepLocked() {
+    boolean goToSleepIfPossible(boolean shuttingDown) {
+        boolean shouldSleep = true;
+
         if (mResumedActivity != null) {
             // Still have something resumed; can't sleep until it is paused.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
@@ -1183,26 +1198,47 @@
             // If we are in the middle of resuming the top activity in
             // {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not
             // resumed yet. We must not proceed pausing the activity here. This method will be
-            // called again if necessary as part of
+            // called again if necessary as part of {@link #checkReadyForSleep} or
             // {@link ActivityStackSupervisor#checkReadyForSleepLocked}.
             if (mStackSupervisor.inResumeTopActivity) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity "
                         + mResumedActivity);
-                return true;
+            } else {
+                startPausingLocked(false, true, null, false);
             }
-
-            startPausingLocked(false, true, null, false);
-            return true;
-        }
-        if (mPausingActivity != null) {
+            shouldSleep = false ;
+        } else if (mPausingActivity != null) {
             // Still waiting for something to pause; can't sleep yet.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
-            return true;
+            shouldSleep = false;
         }
-        return false;
+
+        if (!shuttingDown) {
+            if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
+                // Still need to tell some activities to stop; can't sleep yet.
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
+                        + mStackSupervisor.mStoppingActivities.size() + " activities");
+
+                mStackSupervisor.scheduleIdleLocked();
+                shouldSleep = false;
+            }
+
+            if (containsActivityFromStack(mStackSupervisor.mGoingToSleepActivities)) {
+                // Still need to tell some activities to sleep; can't sleep yet.
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
+                        + mStackSupervisor.mGoingToSleepActivities.size() + " activities");
+                shouldSleep = false;
+            }
+        }
+
+        if (shouldSleep) {
+            goToSleep();
+        }
+
+        return !shouldSleep;
     }
 
-    void goToSleep() {
+    private void goToSleep() {
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
 
         // Make sure any paused or stopped but visible activities are now sleeping.
@@ -1219,6 +1255,15 @@
         }
     }
 
+    private boolean containsActivityFromStack(List<ActivityRecord> rs) {
+        for (ActivityRecord r : rs) {
+            if (r.getStack() == this) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
      * this directly impacts the responsiveness seen by the user.
@@ -1251,7 +1296,7 @@
         if (mPausingActivity != null) {
             Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
                     + " state=" + mPausingActivity.state);
-            if (!mService.isSleepingLocked()) {
+            if (!shouldSleepActivities()) {
                 // Avoid recursion among check for sleep and complete pause during sleeping.
                 // Because activity will be paused immediately after resume, just let pause
                 // be completed by the order of activity paused from clients.
@@ -1411,7 +1456,7 @@
                     // We can't clobber it, because the stop confirmation will not be handled.
                     // We don't need to schedule another stop, we only need to let it happen.
                     prev.state = STOPPING;
-                } else if (!prev.visible || mService.isSleepingOrShuttingDownLocked()) {
+                } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
                     // Clear out any deferred client hide we might currently have.
                     prev.setDeferHidingClient(false);
                     // If we were visible then resumeTopActivities will release resources before
@@ -1433,10 +1478,10 @@
 
         if (resumeNext) {
             final ActivityStack topStack = mStackSupervisor.getFocusedStack();
-            if (!mService.isSleepingOrShuttingDownLocked()) {
+            if (!topStack.shouldSleepOrShutDownActivities()) {
                 mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
             } else {
-                mStackSupervisor.checkReadyForSleepLocked();
+                checkReadyForSleep();
                 ActivityRecord top = topStack.topRunningActivityLocked();
                 if (top == null || (prev != null && top != prev)) {
                     // If there are no more activities available to run, do resume anyway to start
@@ -1502,7 +1547,7 @@
                 mStackSupervisor.scheduleIdleTimeoutLocked(r);
             }
         } else {
-            mStackSupervisor.checkReadyForSleepLocked();
+            checkReadyForSleep();
         }
     }
 
@@ -2211,7 +2256,7 @@
         // is skipped.
         final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
         if (next == null || !next.canTurnScreenOn()) {
-            mStackSupervisor.checkReadyForSleepLocked();
+            checkReadyForSleep();
         }
 
         return result;
@@ -2296,7 +2341,7 @@
 
         // If we are sleeping, and there is no resumed activity, and the top
         // activity is paused, well that is the state we want.
-        if (mService.isSleepingOrShuttingDownLocked()
+        if (shouldSleepOrShutDownActivities()
                 && mLastPausedActivity == next
                 && mStackSupervisor.allPausedActivitiesComplete()) {
             // Make sure we have executed any pending transitions, since there
@@ -2388,7 +2433,7 @@
         // If the most recent activity was noHistory but was only stopped rather
         // than stopped+finished because the device went to sleep, we need to make
         // sure to finish it as we're making a new activity topmost.
-        if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
+        if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
                 !mLastNoHistoryActivity.finishing) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "no-history finish of " + mLastNoHistoryActivity + " on new resume");
@@ -3400,7 +3445,7 @@
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
             if (!r.finishing) {
-                if (!mService.isSleepingLocked()) {
+                if (!shouldSleepActivities()) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
                     if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                             "stop-no-history", false)) {
@@ -3432,7 +3477,7 @@
                 EventLogTags.writeAmStopActivity(
                         r.userId, System.identityHashCode(r), r.shortComponentName);
                 r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
-                if (mService.isSleepingOrShuttingDownLocked()) {
+                if (shouldSleepOrShutDownActivities()) {
                     r.setSleeping(true);
                 }
                 Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
@@ -5278,4 +5323,13 @@
         mNoAnimActivities.clear();
         ActivityOptions.abort(options);
     }
+
+    boolean shouldSleepActivities() {
+        final ActivityStackSupervisor.ActivityDisplay display = getDisplay();
+        return display != null ? display.isSleeping() : mService.isSleepingLocked();
+    }
+
+    boolean shouldSleepOrShutDownActivities() {
+        return shouldSleepActivities() || mService.isShuttingDownLocked();
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e8bc68f..1c18954 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -105,6 +105,7 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.StackInfo;
+import android.app.ActivityManagerInternal.SleepToken;
 import android.app.ActivityOptions;
 import android.app.AppOpsManager;
 import android.app.ProfilerInfo;
@@ -156,6 +157,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.TimeUtils;
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -177,6 +179,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -375,9 +378,6 @@
      * is being brought in front of us. */
     boolean mUserLeaving = false;
 
-    /** Set when we have taken too long waiting to go to sleep. */
-    boolean mSleepTimeout = false;
-
     /**
      * We don't want to allow the device to go to sleep while in the process
      * of launching an activity.  This is primarily to allow alarm intent
@@ -393,6 +393,13 @@
      */
     PowerManager.WakeLock mGoingToSleep;
 
+    /**
+     * A list of tokens that cause the top activity to be put to sleep.
+     * They are used by components that may hide and block interaction with underlying
+     * activities.
+     */
+    final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
+
     /** Stack id of the front stack when user switched, indexed by userId. */
     SparseIntArray mUserStackInFront = new SparseIntArray(2);
 
@@ -3126,6 +3133,16 @@
         return null;
     }
 
+    boolean hasAwakeDisplay() {
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            if (!display.shouldSleep()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void goingToSleepLocked() {
         scheduleSleepTimeout();
         if (!mGoingToSleep.isHeld()) {
@@ -3138,7 +3155,16 @@
                 mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
             }
         }
-        checkReadyForSleepLocked();
+
+        applySleepTokensLocked(false /* applyToStacks */);
+
+        checkReadyForSleepLocked(true /* allowDelay */);
+    }
+
+    void prepareForShutdownLocked() {
+        for (int i = 0; i < mActivityDisplays.size(); i++) {
+            createSleepTokenLocked("shutdown", mActivityDisplays.keyAt(i));
+        }
     }
 
     boolean shutdownLocked(int timeout) {
@@ -3151,7 +3177,8 @@
             for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
                 final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
                 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                    cantShutdown |=
+                            stacks.get(stackNdx).goToSleepIfPossible(true /* shuttingDown */);
                 }
             }
             if (cantShutdown) {
@@ -3172,8 +3199,7 @@
         }
 
         // Force checkReadyForSleep to complete.
-        mSleepTimeout = true;
-        checkReadyForSleepLocked();
+        checkReadyForSleepLocked(false /* allowDelay */);
 
         return timedout;
     }
@@ -3183,54 +3209,75 @@
         if (mGoingToSleep.isHeld()) {
             mGoingToSleep.release();
         }
+    }
+
+    void applySleepTokensLocked(boolean applyToStacks) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            // Set the sleeping state of the display.
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final boolean displayShouldSleep = display.shouldSleep();
+            if (displayShouldSleep == display.isSleeping()) {
+                continue;
+            }
+            display.setIsSleeping(displayShouldSleep);
+
+            if (!applyToStacks) {
+                continue;
+            }
+
+            // Set the sleeping state of the stacks on the display.
+            final ArrayList<ActivityStack> stacks = display.mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                stack.awakeFromSleepingLocked();
-                if (isFocusedStack(stack)) {
-                    resumeFocusedStackTopActivityLocked();
+                if (displayShouldSleep) {
+                    stack.goToSleepIfPossible(false /* shuttingDown */);
+                } else {
+                    stack.awakeFromSleepingLocked();
+                    if (isFocusedStack(stack)) {
+                        resumeFocusedStackTopActivityLocked();
+                    }
+                }
+            }
+
+            if (displayShouldSleep || mGoingToSleepActivities.isEmpty()) {
+                continue;
+            }
+            // The display is awake now, so clean up the going to sleep list.
+            for (Iterator<ActivityRecord> it = mGoingToSleepActivities.iterator(); it.hasNext(); ) {
+                final ActivityRecord r = it.next();
+                if (r.getDisplayId() == display.mDisplayId) {
+                    it.remove();
                 }
             }
         }
-        mGoingToSleepActivities.clear();
     }
 
     void activitySleptLocked(ActivityRecord r) {
         mGoingToSleepActivities.remove(r);
-        checkReadyForSleepLocked();
+        final ActivityStack s = r.getStack();
+        if (s != null) {
+            s.checkReadyForSleep();
+        } else {
+            checkReadyForSleepLocked(true);
+        }
     }
 
-    void checkReadyForSleepLocked() {
+    void checkReadyForSleepLocked(boolean allowDelay) {
         if (!mService.isSleepingOrShuttingDownLocked()) {
             // Do not care.
             return;
         }
 
-        if (!mSleepTimeout) {
+        if (allowDelay) {
             boolean dontSleep = false;
             for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                final ArrayList<ActivityStack> stacks = display.mStacks;
                 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                    dontSleep |= stacks.get(stackNdx).goToSleepIfPossible(false /* shuttingDown */);
                 }
             }
 
-            if (mStoppingActivities.size() > 0) {
-                // Still need to tell some activities to stop; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
-                        + mStoppingActivities.size() + " activities");
-                scheduleIdleLocked();
-                dontSleep = true;
-            }
-
-            if (mGoingToSleepActivities.size() > 0) {
-                // Still need to tell some activities to sleep; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
-                        + mGoingToSleepActivities.size() + " activities");
-                dontSleep = true;
-            }
-
             if (dontSleep) {
                 return;
             }
@@ -3239,13 +3286,6 @@
         // Send launch end powerhint before going sleep
         mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
 
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).goToSleep();
-            }
-        }
-
         removeSleepTimeouts();
 
         if (mGoingToSleep.isHeld()) {
@@ -3516,21 +3556,27 @@
                     s.setVisibility(false);
                 }
             }
-            if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
-                if (!processPausingActivities && s.state == PAUSING) {
-                    // Defer processing pausing activities in this iteration and reschedule
-                    // a delayed idle to reprocess it again
-                    removeTimeoutsForActivityLocked(idleActivity);
-                    scheduleIdleTimeoutLocked(idleActivity);
-                    continue;
-                }
+            if (remove) {
+                final ActivityStack stack = s.getStack();
+                final boolean shouldSleepOrShutDown = stack != null
+                        ? stack.shouldSleepOrShutDownActivities()
+                        : mService.isSleepingOrShuttingDownLocked();
+                if (!waitingVisible || shouldSleepOrShutDown) {
+                    if (!processPausingActivities && s.state == PAUSING) {
+                        // Defer processing pausing activities in this iteration and reschedule
+                        // a delayed idle to reprocess it again
+                        removeTimeoutsForActivityLocked(idleActivity);
+                        scheduleIdleTimeoutLocked(idleActivity);
+                        continue;
+                    }
 
-                if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
-                if (stops == null) {
-                    stops = new ArrayList<>();
+                    if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+                    if (stops == null) {
+                        stops = new ArrayList<>();
+                    }
+                    stops.add(s);
+                    mStoppingActivities.remove(activityNdx);
                 }
-                stops.add(s);
-                mStoppingActivities.remove(activityNdx);
             }
         }
 
@@ -3583,7 +3629,6 @@
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
                 pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
-        pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
         pw.print(prefix);
         pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
@@ -3680,6 +3725,8 @@
                 stackHeader.append("\n");
                 stackHeader.append("  mFullscreen=" + stack.mFullscreen);
                 stackHeader.append("\n");
+                stackHeader.append("  isSleeping=" + stack.shouldSleepActivities());
+                stackHeader.append("\n");
                 stackHeader.append("  mBounds=" + stack.mBounds);
 
                 final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
@@ -3731,8 +3778,6 @@
                 "  Activities waiting for another to become visible:", null);
         printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
                 false, dumpPackage, true, "  Activities waiting to sleep:", null);
-        printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
-                false, dumpPackage, true, "  Activities waiting to sleep:", null);
 
         return printed;
     }
@@ -3843,7 +3888,6 @@
     }
 
     void removeSleepTimeouts() {
-        mSleepTimeout = false;
         mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
     }
 
@@ -3945,6 +3989,9 @@
                         moveTasksToFullscreenStackLocked(stack.getStackId(), true /* onTop */);
                     }
                 }
+
+                releaseSleepTokens(activityDisplay);
+
                 mActivityDisplays.remove(displayId);
                 mWindowManager.onDisplayRemoved(displayId);
             }
@@ -3955,12 +4002,60 @@
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
+                // The window policy is responsible for stopping activities on the default display
+                if (displayId != Display.DEFAULT_DISPLAY) {
+                    int displayState = activityDisplay.mDisplay.getState();
+                    if (displayState == Display.STATE_OFF && activityDisplay.mOffToken == null) {
+                        activityDisplay.mOffToken =
+                                mService.acquireSleepToken("Display-off", displayId);
+                    } else if (displayState == Display.STATE_ON
+                            && activityDisplay.mOffToken != null) {
+                        activityDisplay.mOffToken.release();
+                        activityDisplay.mOffToken = null;
+                    }
+                }
                 // TODO: Update the bounds.
             }
             mWindowManager.onDisplayChanged(displayId);
         }
     }
 
+    SleepToken createSleepTokenLocked(String tag, int displayId) {
+        ActivityDisplay display = mActivityDisplays.get(displayId);
+        if (display == null) {
+            throw new IllegalArgumentException("Invalid display: " + displayId);
+        }
+
+        final SleepTokenImpl token = new SleepTokenImpl(tag, displayId);
+        mSleepTokens.add(token);
+        display.mAllSleepTokens.add(token);
+        return token;
+    }
+
+    private void removeSleepTokenLocked(SleepTokenImpl token) {
+        mSleepTokens.remove(token);
+
+        ActivityDisplay display = mActivityDisplays.get(token.mDisplayId);
+        if (display != null) {
+            display.mAllSleepTokens.remove(token);
+            if (display.mAllSleepTokens.isEmpty()) {
+                mService.updateSleepIfNeededLocked();
+            }
+        }
+    }
+
+    private void releaseSleepTokens(ActivityDisplay display) {
+        if (display.mAllSleepTokens.isEmpty()) {
+            return;
+        }
+        for (SleepTokenImpl token : display.mAllSleepTokens) {
+            mSleepTokens.remove(token);
+        }
+        display.mAllSleepTokens.clear();
+
+        mService.updateSleepIfNeededLocked();
+    }
+
     private StackInfo getStackInfoLocked(ActivityStack stack) {
         final int displayId = stack.mDisplayId;
         final ActivityDisplay display = mActivityDisplays.get(displayId);
@@ -4266,9 +4361,9 @@
 
     void activityRelaunchedLocked(IBinder token) {
         mWindowManager.notifyAppRelaunchingFinished(token);
-        if (mService.isSleepingOrShuttingDownLocked()) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r != null) {
+        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+        if (r != null) {
+            if (r.getStack().shouldSleepOrShutDownActivities()) {
                 r.setSleeping(true, true);
             }
         }
@@ -4420,8 +4515,7 @@
                     synchronized (mService) {
                         if (mService.isSleepingOrShuttingDownLocked()) {
                             Slog.w(TAG, "Sleep timeout!  Sleeping now.");
-                            mSleepTimeout = true;
-                            checkReadyForSleepLocked();
+                            checkReadyForSleepLocked(false /* allowDelay */);
                         }
                     }
                 } break;
@@ -4546,6 +4640,13 @@
         /** Array of all UIDs that are present on the display. */
         private IntArray mDisplayAccessUIDs = new IntArray();
 
+        /** All tokens used to put activities on this stack to sleep (including mOffToken) */
+        final ArrayList<SleepTokenImpl> mAllSleepTokens = new ArrayList<>();
+        /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
+        SleepToken mOffToken;
+
+        private boolean mSleeping;
+
         @VisibleForTesting
         ActivityDisplay() {
             mActivityDisplays.put(mDisplayId, this);
@@ -4570,12 +4671,14 @@
             if (DEBUG_STACK) Slog.v(TAG_STACK, "attachStack: attaching " + stack
                     + " to displayId=" + mDisplayId + " position=" + position);
             mStacks.add(position, stack);
+            mService.updateSleepIfNeededLocked();
         }
 
         void detachStack(ActivityStack stack) {
             if (DEBUG_STACK) Slog.v(TAG_STACK, "detachStack: detaching " + stack
                     + " from displayId=" + mDisplayId);
             mStacks.remove(stack);
+            mService.updateSleepIfNeededLocked();
         }
 
         @Override
@@ -4623,6 +4726,19 @@
         boolean shouldDestroyContentOnRemove() {
             return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
         }
+
+        boolean shouldSleep() {
+            return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
+                    && (mService.mRunningVoice == null);
+        }
+
+        boolean isSleeping() {
+            return mSleeping;
+        }
+
+        void setIsSleeping(boolean asleep) {
+            mSleeping = asleep;
+        }
     }
 
     ActivityStack findStackBehind(ActivityStack stack) {
@@ -4804,4 +4920,30 @@
             mResult.dump(pw, prefix);
         }
     }
+
+    private final class SleepTokenImpl extends SleepToken {
+        private final String mTag;
+        private final long mAcquireTime;
+        private final int mDisplayId;
+
+        public SleepTokenImpl(String tag, int displayId) {
+            mTag = tag;
+            mDisplayId = displayId;
+            mAcquireTime = SystemClock.uptimeMillis();
+        }
+
+        @Override
+        public void release() {
+            synchronized (mService) {
+                removeSleepTokenLocked(this);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "{\"" + mTag + "\", display " + mDisplayId
+                    + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 58e71df..cea80c8 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -32,6 +33,7 @@
 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 
+import android.app.ActivityManagerInternal.SleepToken;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -63,6 +65,7 @@
     private ActivityRecord mDismissingKeyguardActivity;
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
+    private SleepToken mSleepToken;
 
     KeyguardController(ActivityManagerService service,
             ActivityStackSupervisor stackSupervisor) {
@@ -102,7 +105,7 @@
             mDismissalRequested = false;
         }
         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        mService.updateSleepIfNeededLocked();
+        updateKeyguardSleepToken();
     }
 
     /**
@@ -122,7 +125,7 @@
             mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                     false /* alwaysKeepCurrent */, convertTransitFlags(flags),
                     false /* forceOverride */);
-            mService.updateSleepIfNeededLocked();
+            updateKeyguardSleepToken();
 
             // Some stack visibility might change (e.g. docked stack)
             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -263,7 +266,7 @@
             try {
                 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
-                mService.updateSleepIfNeededLocked();
+                updateKeyguardSleepToken();
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 mWindowManager.executeAppTransition();
             } finally {
@@ -333,6 +336,15 @@
         }
     }
 
+    private void updateKeyguardSleepToken() {
+        if (mSleepToken == null && isKeyguardShowing()) {
+            mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
+        } else if (mSleepToken != null && !isKeyguardShowing()) {
+            mSleepToken.release();
+            mSleepToken = null;
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "KeyguardController:");
         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 88d8944..261797e3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -96,6 +96,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -1293,7 +1294,6 @@
             // created controller for the activity we are starting yet.
             mWindowContainerController.positionChildAt(appController, index);
         }
-        r.onOverrideConfigurationSent();
 
         // Make sure the list of display UID whitelists is updated
         // now that this record is in a new task.
@@ -1580,8 +1580,9 @@
         // A task can not be docked even if it is considered resizeable because it only supports
         // picture-in-picture mode but has a non-resizeable resizeMode
         return mService.mSupportsSplitScreenMultiWindow
-                && isResizeable(false /* checkSupportsPip */)
-                && !ActivityInfo.isPreserveOrientationMode(mResizeMode);
+                && (mService.mForceResizableActivities
+                        || (isResizeable(false /* checkSupportsPip */)
+                                && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e82eabf..56cff7c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -305,8 +305,8 @@
      * In order to support the always-on feature, an app has to
      * <ul>
      *     <li>target {@link VERSION_CODES#N API 24} or above, and
-     *     <li>not opt out through the {@link VpnService#METADATA_SUPPORTS_ALWAYS_ON} meta-data
-     *         field.
+     *     <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+     *         meta-data field.
      * </ul>
      *
      * @param packageName the canonical package name of the VPN app
@@ -340,8 +340,8 @@
 
         for (ResolveInfo rInfo : services) {
             final Bundle metaData = rInfo.serviceInfo.metaData;
-            if (metaData != null
-                    && !metaData.getBoolean(VpnService.METADATA_SUPPORTS_ALWAYS_ON, true)) {
+            if (metaData != null &&
+                    !metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) {
                 return false;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 55e290a..4393e35 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -17,7 +17,9 @@
 package com.android.server.connectivity.tethering;
 
 import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.STATS_PER_UID;
 import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
 import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
 
@@ -60,6 +62,8 @@
     private final Handler mHandler;
     private final OffloadHardwareInterface mHwInterface;
     private final ContentResolver mContentResolver;
+    private final INetworkManagementService mNms;
+    private final ITetheringStatsProvider mStatsProvider;
     private final SharedLog mLog;
     private boolean mConfigInitialized;
     private boolean mControlInitialized;
@@ -89,13 +93,14 @@
         mHandler = h;
         mHwInterface = hwi;
         mContentResolver = contentResolver;
+        mNms = nms;
+        mStatsProvider = new OffloadTetheringStatsProvider();
         mLog = log.forSubComponent(TAG);
         mExemptPrefixes = new HashSet<>();
         mLastLocalPrefixStrs = new HashSet<>();
 
         try {
-            nms.registerTetheringStatsProvider(
-                    new OffloadTetheringStatsProvider(), getClass().getSimpleName());
+            mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName());
         } catch (RemoteException e) {
             mLog.e("Cannot register offload stats provider: " + e);
         }
@@ -150,7 +155,26 @@
                     @Override
                     public void onStoppedLimitReached() {
                         mLog.log("onStoppedLimitReached");
-                        // Poll for statistics and notify NetworkStats
+
+                        // We cannot reliably determine on which interface the limit was reached,
+                        // because the HAL interface does not specify it. We cannot just use the
+                        // current upstream, because that might have changed since the time that
+                        // the HAL queued the callback.
+                        // TODO: rev the HAL so that it provides an interface name.
+
+                        // Fetch current stats, so that when our notification reaches
+                        // NetworkStatsService and triggers a poll, we will respond with
+                        // current data (which will be above the limit that was reached).
+                        // Note that if we just changed upstream, this is unnecessary but harmless.
+                        // The stats for the previous upstream were already updated on this thread
+                        // just after the upstream was changed, so they are also up-to-date.
+                        updateStatsForCurrentUpstream();
+
+                        try {
+                            mNms.tetherLimitReached(mStatsProvider);
+                        } catch (RemoteException e) {
+                            mLog.e("Cannot report data limit reached: " + e);
+                        }
                     }
 
                     @Override
@@ -180,16 +204,18 @@
 
     private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub {
         @Override
-        public NetworkStats getTetherStats() {
+        public NetworkStats getTetherStats(int how) {
             NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
 
             // We can't just post to mHandler because we are mostly (but not always) called by
             // NetworkStatsService#performPollLocked, which is (currently) on the same thread as us.
             mHandler.runWithScissors(() -> {
+                // We have to report both per-interface and per-UID stats, because offloaded traffic
+                // is not seen by kernel interface counters.
                 NetworkStats.Entry entry = new NetworkStats.Entry();
                 entry.set = SET_DEFAULT;
                 entry.tag = TAG_NONE;
-                entry.uid = UID_TETHERING;
+                entry.uid = (how == STATS_PER_UID) ? UID_TETHERING : UID_ALL;
 
                 updateStatsForCurrentUpstream();
 
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index ad74ff8..6e1c21e 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -646,6 +646,7 @@
         SyncManager syncManager = getSyncManager();
         if (syncManager == null) return;
         int userId = UserHandle.getCallingUserId();
+        final int callingUid = Binder.getCallingUid();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -658,7 +659,8 @@
                 // Remove periodic sync.
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                         "no permission to write the sync settings");
-                getSyncManager().removePeriodicSync(info, extras);
+                getSyncManager().removePeriodicSync(info, extras,
+                        "cancelRequest() by uid=" + callingUid);
             }
             // Cancel active syncs and clear pending syncs from the queue.
             syncManager.cancelScheduledSyncOperation(info, extras);
@@ -814,13 +816,15 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
 
+        final int callingUid = Binder.getCallingUid();
+
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             getSyncManager()
                     .removePeriodicSync(
                             new SyncStorageEngine.EndPoint(account, authority, userId),
-                            extras);
+                            extras, "removePeriodicSync() by uid=" + callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f41aa5f..845561f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -59,6 +59,7 @@
 import android.net.TrafficStats;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -141,6 +142,8 @@
 
     private static final boolean DEBUG_ACCOUNT_ACCESS = false;
 
+    private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
+
     /** Delay a sync due to local changes this long. In milliseconds */
     private static final long LOCAL_SYNC_DELAY;
 
@@ -463,7 +466,7 @@
                         }
                         if (opx.key.equals(opy.key)) {
                             mLogger.log("Removing duplicate sync: ", opy);
-                            mJobScheduler.cancel(opy.jobId);
+                            cancelJob(opy, "cleanupJobs() x=" + opx + " y=" + opy);
                         }
                     }
                 }
@@ -501,15 +504,21 @@
                     }
                 }
             }
-            if (mLogger.enabled()) {
-                mLogger.log("Connected to JobScheduler: "
-                        + numPersistedPeriodicSyncs + " periodic syncs "
-                        + numPersistedOneshotSyncs + " oneshot syncs.");
-            }
+            final int totalJobs = (mJobSchedulerInternal == null)
+                    ? -1 : mJobSchedulerInternal.countJobs();
+            final String summary = "Loaded persisted syncs: "
+                    + numPersistedPeriodicSyncs + " periodic syncs, "
+                    + numPersistedOneshotSyncs + " oneshot syncs, "
+                    + (pendingJobs.size()) + " total system server jobs, "
+                    + totalJobs + " total jobs.";
+            Slog.i(TAG, summary);
+            mLogger.log(summary);
+
             cleanupJobs();
 
-            if ((numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
-                Slog.wtf(TAG, "Device booted with no persisted periodic syncs.");
+            if (ENABLE_SUSPICIOUS_CHECK &&
+                    (numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
+                Slog.wtf(TAG, "Device booted with no persisted periodic syncs: " + summary);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -520,6 +529,7 @@
      * @return whether the device most likely has some periodic syncs.
      */
     private boolean likelyHasPeriodicSyncs() {
+        // STOPSHIP Remove the google specific string.
         try {
             return AccountManager.get(mContext).getAccountsByType("com.google").length > 0;
         } catch (Throwable th) {
@@ -566,7 +576,7 @@
         mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
             @Override
             public void onAuthorityRemoved(EndPoint removedAuthority) {
-                removeSyncsForAuthority(removedAuthority);
+                removeSyncsForAuthority(removedAuthority, "onAuthorityRemoved");
             }
         });
 
@@ -1118,14 +1128,14 @@
         }
     }
 
-    private void removeSyncsForAuthority(EndPoint info) {
+    private void removeSyncsForAuthority(EndPoint info, String why) {
         mLogger.log("removeSyncsForAuthority: ", info);
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (op.target.matchesSpec(info)) {
                 mLogger.log("canceling: ", op);
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, why);
             }
         }
     }
@@ -1133,8 +1143,9 @@
     /**
      * Remove a specific periodic sync identified by its target and extras.
      */
-    public void removePeriodicSync(EndPoint target, Bundle extras) {
-        Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC, target);
+    public void removePeriodicSync(EndPoint target, Bundle extras, String why) {
+        Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC,
+                Pair.create(target, why));
         m.setData(extras);
         m.sendToTarget();
     }
@@ -1359,7 +1370,7 @@
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(target)) {
                 count++;
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, why);
                 postScheduleSyncMessage(op, 0 /* min delay */);
             }
         }
@@ -1484,7 +1495,7 @@
                         if (isLoggable) {
                             Slog.v(TAG, "Cancelling duplicate sync " + op);
                         }
-                        getJobScheduler().cancel(op.jobId);
+                        cancelJob(op, "scheduleSyncOperationH-duplicate");
                     }
                 }
             }
@@ -1544,7 +1555,7 @@
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(info)) {
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, "clearScheduledSyncOperations");
                 getSyncStorageEngine().markPending(op.target, false);
             }
         }
@@ -1562,7 +1573,7 @@
         for (SyncOperation op: ops) {
             if (!op.isPeriodic && op.target.matchesSpec(info)
                     && syncExtrasEquals(extras, op.extras, false)) {
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, "cancelScheduledSyncOperation");
             }
         }
         setAuthorityPendingState(info);
@@ -1678,7 +1689,7 @@
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (op.target.userId == userId) {
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, "user removed u" + userId);
             }
         }
     }
@@ -2710,7 +2721,8 @@
                                 data.flex, data.extras);
                         break;
                     case MESSAGE_REMOVE_PERIODIC_SYNC:
-                        removePeriodicSyncH((EndPoint)msg.obj, msg.getData());
+                        Pair<EndPoint, String> args = (Pair<EndPoint, String>) (msg.obj);
+                        removePeriodicSyncH(args.first, msg.getData(), args.second);
                         break;
 
                     case SyncHandler.MESSAGE_CANCEL:
@@ -2848,7 +2860,7 @@
                 // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
                 // find the this job in the pending jobs list while looking for duplicates
                 // before scheduling it at a later time.
-                getJobScheduler().cancel(op.jobId);
+                cancelJob(op, "deferSyncH()");
                 scheduleSyncOperationH(op, delay);
             }
         }
@@ -2998,7 +3010,7 @@
             for (SyncOperation op: ops) {
                 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
                     mLogger.log("canceling: ", op);
-                    getJobScheduler().cancel(op.jobId);
+                    cancelJob(op, "updateRunningAccountsH()");
                 }
             }
 
@@ -3105,7 +3117,7 @@
         /**
          * Remove this periodic sync operation and all one-off operations initiated by it.
          */
-        private void removePeriodicSyncInternalH(SyncOperation syncOperation) {
+        private void removePeriodicSyncInternalH(SyncOperation syncOperation, String why) {
             // Remove this periodic sync and all one-off syncs initiated by it.
             List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
@@ -3117,18 +3129,18 @@
                         runSyncFinishedOrCanceledH(null, asc);
                     }
                     mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
-                    getJobScheduler().cancel(op.jobId);
+                    cancelJob(op, why);
                 }
             }
         }
 
-        private void removePeriodicSyncH(EndPoint target, Bundle extras) {
+        private void removePeriodicSyncH(EndPoint target, Bundle extras, String why) {
             verifyJobScheduler();
             List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (op.isPeriodic && op.target.matchesSpec(target)
                         && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
-                    removePeriodicSyncInternalH(op);
+                    removePeriodicSyncInternalH(op, why);
                 }
             }
         }
@@ -3354,12 +3366,6 @@
             int downstreamActivity;
             int upstreamActivity;
 
-            if (!syncOperation.isPeriodic) {
-                // mSyncJobService.jobFinidhed is async, we need to ensure that this job is
-                // removed from JobScheduler's pending jobs list before moving forward and
-                // potentially rescheduling all pending jobs to respect new backoff values.
-                getJobScheduler().cancel(syncOperation.jobId);
-            }
             mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
 
             if (syncResult != null) {
@@ -3368,6 +3374,16 @@
                             + syncOperation + ", result " + syncResult);
                 }
 
+                // In the non-canceled case, close the active sync context before doing the rest
+                // of the stuff.
+                closeActiveSyncContext(activeSyncContext);
+
+                // Note this part is probably okay to do before closeActiveSyncContext()...
+                // But moved here to restore OC-dev's behavior.  See b/64597061.
+                if (!syncOperation.isPeriodic) {
+                    cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-finished");
+                }
+
                 if (!syncResult.hasError()) {
                     historyMessage = SyncStorageEngine.MESG_SUCCESS;
                     // TODO: set these correctly when the SyncResult is extended to include it
@@ -3404,6 +3420,11 @@
                 if (isLoggable) {
                     Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
                 }
+
+                if (!syncOperation.isPeriodic) {
+                    cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-canceled");
+                }
+
                 if (activeSyncContext.mSyncAdapter != null) {
                     try {
                         mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
@@ -3418,10 +3439,10 @@
                 historyMessage = SyncStorageEngine.MESG_CANCELED;
                 downstreamActivity = 0;
                 upstreamActivity = 0;
-            }
 
-            // Close and unbind the service.  Don't use activeSyncContext.mSyncAdapter after this.
-            closeActiveSyncContext(activeSyncContext);
+                // In the cancel sync case, close it after calling cancelSync().
+                closeActiveSyncContext(activeSyncContext);
+            }
 
             stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
                     upstreamActivity, downstreamActivity, elapsedTime);
@@ -3457,6 +3478,8 @@
                         + activeSyncContext.toString());
             }
             mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
+
+            mLogger.log("closeActiveSyncContext: ", activeSyncContext);
         }
 
         /**
@@ -3736,4 +3759,48 @@
             return mContext;
         }
     }
+
+    private void cancelJob(SyncOperation op, String why) {
+        if (op == null) {
+            Slog.wtf(TAG, "Null sync operation detected.");
+            return;
+        }
+        if (op.isPeriodic) {
+            mLogger.log("Removing periodic sync ", op, " for ", why);
+
+            if (ENABLE_SUSPICIOUS_CHECK && isSuspiciousPeriodicSyncRemoval(op)) {
+                wtfWithLog("Suspicious removal of " + op + " for " + why);
+            }
+        }
+        getJobScheduler().cancel(op.jobId);
+    }
+
+    private boolean isSuspiciousPeriodicSyncRemoval(SyncOperation op) {
+        // STOPSHIP Remove the google specific string.
+        if (!op.isPeriodic){
+            return false;
+        }
+        switch (op.target.provider) {
+            case "gmail-ls":
+            case "com.android.contacts.metadata":
+                break;
+            default:
+                return false;
+        }
+        final Account account = op.target.account;
+        final Account[] accounts = AccountManager.get(mContext)
+                .getAccountsByTypeAsUser(account.type, UserHandle.of(op.target.userId));
+        for (Account a : accounts) {
+            if (a.equals(account)) {
+                return true; // Account still exists.  Suspicious!
+            }
+        }
+        // Account no longer exists. Makes sense...
+        return false;
+    }
+
+    private void wtfWithLog(String message) {
+        Slog.wtf(TAG, message);
+        mLogger.log("WTF: ", message);
+    }
 }
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 3d24fed..9aabdab 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -59,6 +59,13 @@
     private static final int MSG_UPDATE_AMBIENT_LUX = 1;
     private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
 
+    // Length of the ambient light horizon used to calculate the long term estimate of ambient
+    // light.
+    private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
+
+    // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
+    private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
+
     // Callbacks for requesting updates to the display's power state
     private final Callbacks mCallbacks;
 
@@ -345,22 +352,51 @@
     }
 
     private void setAmbientLux(float lux) {
+        if (DEBUG) {
+            Slog.d(TAG, "setAmbientLux(" + lux + ")");
+        }
         mAmbientLux = lux;
         mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
         mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
     }
 
-    private float calculateAmbientLux(long now) {
+    private float calculateAmbientLux(long now, long horizon) {
+        if (DEBUG) {
+            Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
+        }
         final int N = mAmbientLightRingBuffer.size();
         if (N == 0) {
             Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
             return -1;
         }
+
+        // Find the first measurement that is just outside of the horizon.
+        int endIndex = 0;
+        final long horizonStartTime = now - horizon;
+        for (int i = 0; i < N-1; i++) {
+            if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
+                endIndex++;
+            } else {
+                break;
+            }
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=("
+                    + mAmbientLightRingBuffer.getTime(endIndex) + ", "
+                    + mAmbientLightRingBuffer.getLux(endIndex)
+                    + ")");
+        }
         float sum = 0;
         float totalWeight = 0;
         long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
-        for (int i = N - 1; i >= 0; i--) {
-            long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
+        for (int i = N - 1; i >= endIndex; i--) {
+            long eventTime = mAmbientLightRingBuffer.getTime(i);
+            if (i == endIndex && eventTime < horizonStartTime) {
+                // If we're at the final value, make sure we only consider the part of the sample
+                // within our desired horizon.
+                eventTime = horizonStartTime;
+            }
+            final long startTime = eventTime - now;
             float weight = calculateWeight(startTime, endTime);
             float lux = mAmbientLightRingBuffer.getLux(i);
             if (DEBUG) {
@@ -435,7 +471,7 @@
                         timeWhenSensorWarmedUp);
                 return;
             }
-            setAmbientLux(calculateAmbientLux(time));
+            setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
             mAmbientLuxValid = true;
             if (DEBUG) {
                 Slog.d(TAG, "updateAmbientLux: Initializing: "
@@ -447,14 +483,25 @@
 
         long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
         long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
-        float ambientLux = calculateAmbientLux(time);
+        // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
+        // change in lighting conditions, and a fast ambient lux to determine what the new
+        // brightness situation is since the slow lux can be quite slow to converge.
+        //
+        // Note that both values need to be checked for sufficient change before updating the
+        // proposed ambient light value since the slow value might be sufficiently far enough away
+        // from the fast value to cause a recalculation while its actually just converging on
+        // the fast value still.
+        float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
+        float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
 
-        if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
-                || ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
-            setAmbientLux(ambientLux);
+        if (slowAmbientLux >= mBrighteningLuxThreshold &&
+                fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
+                || slowAmbientLux <= mDarkeningLuxThreshold
+                && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
+            setAmbientLux(fastAmbientLux);
             if (DEBUG) {
                 Slog.d(TAG, "updateAmbientLux: "
-                        + ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+                        + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
                         + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
                         + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
                         + ", mAmbientLux=" + mAmbientLux);
@@ -616,6 +663,12 @@
         void updateBrightness();
     }
 
+    /**
+     * A ring buffer of ambient light measurements sorted by time.
+     *
+     * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
+     * from oldest to newest.
+     */
     private static final class AmbientLightRingBuffer {
         // Proportional extra capacity of the buffer beyond the expected number of light samples
         // in the horizon
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index fb8ae12..e316fff 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1010,7 +1010,9 @@
             // contents of the screen.
             mPowerState.prepareColorFade(mContext,
                     mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP);
-            mColorFadeOffAnimator.end();
+            if (mColorFadeOffAnimator != null) {
+                mColorFadeOffAnimator.end();
+            }
             // Some display hardware will blank itself on the transition between doze and non-doze
             // but still on display states. In this case we want to report to policy that the
             // display has turned off so it can prepare the appropriate power on animation, but we
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
index bc6bd50..d52b3b7 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -37,4 +37,9 @@
     void addBackingUpUid(int uid);
     void removeBackingUpUid(int uid);
     void clearAllBackingUpUids();
+
+    /**
+     * @return the total number of jobs across all UIDs.
+     */
+    int countJobs();
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index e25f3e6..12087b0 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1835,6 +1835,13 @@
                 }
             }
         }
+
+        @Override
+        public int countJobs() {
+            synchronized (mLock) {
+                return mJobs.size();
+            }
+        }
     }
 
     /**
@@ -2015,6 +2022,12 @@
         @Override
         public void cancelAll() throws RemoteException {
             final int uid = Binder.getCallingUid();
+            switch (uid) {
+                case Process.SYSTEM_UID:
+                    // This really shouldn't happen.
+                    Slog.wtf(TAG, "JobScheduler.cancelAll() called for uid=" + uid);
+                    return;
+            }
 
             long ident = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 62b06d6..5317616 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -544,6 +544,7 @@
 
         @Override
         public void run() {
+            int numJobs = 0;
             try {
                 List<JobStatus> jobs;
                 FileInputStream fis = mJobsFile.openRead();
@@ -557,6 +558,7 @@
                             js.prepareLocked(am);
                             js.enqueueTime = now;
                             this.jobSet.add(js);
+                            numJobs++;
                         }
                     }
                 }
@@ -565,15 +567,10 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
                 }
-            } catch (XmlPullParserException e) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error parsing xml.", e);
-                }
-            } catch (IOException e) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error parsing xml.", e);
-                }
+            } catch (XmlPullParserException | IOException e) {
+                Slog.wtf(TAG, "Error jobstore xml.", e);
             }
+            Slog.i(TAG, "Read " + numJobs + " jobs");
         }
 
         private List<JobStatus> readJobMapImpl(FileInputStream fis, boolean rtcIsGood)
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 83bacc2..5927b2f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
@@ -77,6 +78,7 @@
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 
@@ -559,6 +561,10 @@
 
     @Override // binder interface
     public void systemReady() {
+        if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
+        }
+        checkWritePermission(UserHandle.USER_SYSTEM);
         migrateOldData();
         try {
             getGateKeeperService();
@@ -805,6 +811,13 @@
         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
     }
 
+    private final void checkPasswordHavePermission(int userId) {
+        if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
+        }
+        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
+    }
+
     private final void checkReadPermission(String requestedKey, int userId) {
         final int callingUid = Binder.getCallingUid();
 
@@ -934,6 +947,7 @@
 
     @Override
     public boolean havePassword(int userId) throws RemoteException {
+        checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 long handle = getSyntheticPasswordHandleLocked(userId);
@@ -947,6 +961,7 @@
 
     @Override
     public boolean havePattern(int userId) throws RemoteException {
+        checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 long handle = getSyntheticPasswordHandleLocked(userId);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0072ba4..f88a074 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3046,9 +3046,7 @@
                 updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
                 if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
                         != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
-                    if (isUidIdle(uid)) {
-                        updateRuleForAppIdleUL(uid);
-                    }
+                    updateRuleForAppIdleUL(uid);
                     if (mDeviceIdleMode) {
                         updateRuleForDeviceIdleUL(uid);
                     }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8209ade..b14aa13 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -29,6 +29,8 @@
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
+import static android.net.NetworkStats.STATS_PER_IFACE;
+import static android.net.NetworkStats.STATS_PER_UID;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
@@ -1041,6 +1043,11 @@
         final NetworkStats xtSnapshot = getNetworkStatsXt();
         final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
 
+        // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats
+        // providers that isn't already counted by dev and XT stats.
+        final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE);
+        xtSnapshot.combineAllValues(tetherSnapshot);
+        devSnapshot.combineAllValues(tetherSnapshot);
 
         // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic
         // can't be reattributed to responsible apps.
@@ -1371,14 +1378,14 @@
         final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
 
         // fold tethering stats and operations into uid snapshot
-        final NetworkStats tetherSnapshot = getNetworkStatsTethering();
+        final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
         uidSnapshot.combineAllValues(tetherSnapshot);
 
         final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
                 Context.TELEPHONY_SERVICE);
 
         // fold video calling data usage stats into uid snapshot
-        final NetworkStats vtStats = telephonyManager.getVtDataUsage(true);
+        final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
         if (vtStats != null) {
             uidSnapshot.combineAllValues(vtStats);
         }
@@ -1397,7 +1404,7 @@
                 Context.TELEPHONY_SERVICE);
 
         // Merge video calling data usage into XT
-        final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(false);
+        final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE);
         if (vtSnapshot != null) {
             xtSnapshot.combineAllValues(vtSnapshot);
         }
@@ -1409,9 +1416,9 @@
      * Return snapshot of current tethering statistics. Will return empty
      * {@link NetworkStats} if any problems are encountered.
      */
-    private NetworkStats getNetworkStatsTethering() throws RemoteException {
+    private NetworkStats getNetworkStatsTethering(int how) throws RemoteException {
         try {
-            return mNetworkManager.getNetworkStatsTethering();
+            return mNetworkManager.getNetworkStatsTethering(how);
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem reading network stats", e);
             return new NetworkStats(0L, 10);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index beaddb4..d5d0250 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -877,6 +877,7 @@
 
                 @Override
                 public void onServiceDisconnected(ComponentName name) {
+                    mServicesBinding.remove(servicesBindingTag);
                     Slog.v(TAG, getCaption() + " connection lost: " + name);
                 }
             };
@@ -889,6 +890,7 @@
                 return;
             }
         } catch (SecurityException ex) {
+            mServicesBinding.remove(servicesBindingTag);
             Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 28acd9a..f60d923 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -804,6 +804,7 @@
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
                 mZenModeHelper.updateDefaultZenRules();
+                mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
             }
         }
     };
@@ -3104,7 +3105,7 @@
             }
         }
         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
-                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
+                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
         }
     }
@@ -3449,7 +3450,8 @@
                 user, null, System.currentTimeMillis());
         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
 
-        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
+        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
+                r.sbn.getOverrideGroupKey() != null)) {
             return;
         }
 
@@ -3504,7 +3506,7 @@
      * Has side effects.
      */
     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
-            NotificationRecord r) {
+            NotificationRecord r, boolean isAutogroup) {
         final String pkg = r.sbn.getPackageName();
         final String dialerPackage =
                 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
@@ -3528,7 +3530,8 @@
 
                 // rate limit updates that aren't completed progress notifications
                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
-                        && !r.getNotification().hasCompletedProgress()) {
+                        && !r.getNotification().hasCompletedProgress()
+                        && !isAutogroup) {
 
                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
@@ -3536,7 +3539,7 @@
                         final long now = SystemClock.elapsedRealtime();
                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
-                                    + ". Shedding events. package=" + pkg);
+                                    + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
                             mLastOverRateLogTime = now;
                         }
                         return false;
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 9622a24..3386fe83 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -1073,6 +1073,22 @@
         }
     }
 
+    protected void onLocaleChanged(Context context, int userId) {
+        synchronized (mRecords) {
+            int N = mRecords.size();
+            for (int i = 0; i < N; i++) {
+                Record record = mRecords.valueAt(i);
+                if (UserHandle.getUserId(record.uid) == userId) {
+                    if (record.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+                        record.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(
+                                context.getResources().getString(
+                                        R.string.default_notification_channel_label));
+                    }
+                }
+            }
+        }
+    }
+
     public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
             int[] uidList) {
         if (pkgList == null || pkgList.length == 0) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 43e0affb..529fcc4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -85,6 +85,8 @@
 import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDWR;
 
@@ -3884,8 +3886,7 @@
                 throw new SecurityException("Package " + packageName + " is currently frozen!");
             }
 
-            if (!userKeyUnlocked && !(ps.pkg.applicationInfo.isDirectBootAware()
-                    || ps.pkg.applicationInfo.isPartiallyDirectBootAware())) {
+            if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) {
                 throw new SecurityException("Package " + packageName + " is not encryption aware!");
             }
         }
@@ -19758,6 +19759,10 @@
 
         // writer
         synchronized (mPackages) {
+            // NOTE: The system package always needs to be enabled; even if it's for
+            // a compressed stub. If we don't, installing the system package fails
+            // during scan [scanning checks the disabled packages]. We will reverse
+            // this later, after we've "installed" the stub.
             // Reinstate the old system package
             enableSystemPackageLPw(disabledPs.pkg);
             // Remove any native libraries from the upgraded package.
@@ -19766,23 +19771,38 @@
 
         // Install the system package
         if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
-        int parseFlags = mDefParseFlags
-                | PackageParser.PARSE_MUST_BE_APK
-                | PackageParser.PARSE_IS_SYSTEM
-                | PackageParser.PARSE_IS_SYSTEM_DIR;
-        if (locationIsPrivileged(disabledPs.codePath)) {
-            parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
-        }
-
-        final PackageParser.Package newPkg;
         try {
-            newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, 0 /* scanFlags */,
-                0 /* currentTime */, null);
+            installPackageFromSystemLIF(disabledPs.codePath, false /*isPrivileged*/, allUserHandles,
+                    outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
                     + e.getMessage());
             return false;
+        } finally {
+            if (disabledPs.pkg.isStub) {
+                mSettings.disableSystemPackageLPw(disabledPs.name, true /*replaced*/);
+            }
         }
+        return true;
+    }
+
+    /**
+     * Installs a package that's already on the system partition.
+     */
+    private PackageParser.Package installPackageFromSystemLIF(@NonNull File codePath,
+            boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
+            @Nullable PermissionsState origPermissionState, boolean writeSettings)
+                    throws PackageManagerException {
+        int parseFlags = mDefParseFlags
+                | PackageParser.PARSE_MUST_BE_APK
+                | PackageParser.PARSE_IS_SYSTEM
+                | PackageParser.PARSE_IS_SYSTEM_DIR;
+        if (isPrivileged || locationIsPrivileged(codePath)) {
+            parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
+        }
+
+        final PackageParser.Package newPkg =
+                scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, 0 /*currentTime*/, null);
 
         try {
             // update shared libraries for the newly re-installed system package
@@ -19800,17 +19820,21 @@
             // Propagate the permissions state as we do not want to drop on the floor
             // runtime permissions. The update permissions method below will take
             // care of removing obsolete permissions and grant install permissions.
-            ps.getPermissionsState().copyFrom(deletedPs.getPermissionsState());
+            if (origPermissionState != null) {
+                ps.getPermissionsState().copyFrom(origPermissionState);
+            }
             updatePermissionsLPw(newPkg.packageName, newPkg,
                     UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
 
+            final boolean applyUserRestrictions
+                    = (allUserHandles != null) && (origUserHandles != null);
             if (applyUserRestrictions) {
                 boolean installedStateChanged = false;
                 if (DEBUG_REMOVE) {
                     Slog.d(TAG, "Propagating install state across reinstall");
                 }
                 for (int userId : allUserHandles) {
-                    final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
+                    final boolean installed = ArrayUtils.contains(origUserHandles, userId);
                     if (DEBUG_REMOVE) {
                         Slog.d(TAG, "    user " + userId + " => " + installed);
                     }
@@ -19833,7 +19857,7 @@
                 mSettings.writeLPr();
             }
         }
-        return true;
+        return newPkg;
     }
 
     private boolean deleteInstalledPackageLIF(PackageSetting ps,
@@ -21766,77 +21790,183 @@
             }
         }
 
-        synchronized (mPackages) {
-            if (callingUid == Process.SHELL_UID
-                    && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
-                // Shell can only change whole packages between ENABLED and DISABLED_USER states
-                // unless it is a test package.
-                int oldState = pkgSetting.getEnabled(userId);
-                if (className == null
-                    &&
-                    (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                     || oldState == COMPONENT_ENABLED_STATE_DEFAULT
-                     || oldState == COMPONENT_ENABLED_STATE_ENABLED)
-                    &&
-                    (newState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                     || newState == COMPONENT_ENABLED_STATE_DEFAULT
-                     || newState == COMPONENT_ENABLED_STATE_ENABLED)) {
-                    // ok
-                } else {
-                    throw new SecurityException(
-                            "Shell cannot change component state for " + packageName + "/"
-                            + className + " to " + newState);
-                }
-            }
-            if (className == null) {
-                // We're dealing with an application/package level state change
-                if (pkgSetting.getEnabled(userId) == newState) {
-                    // Nothing to do
-                    return;
-                }
-                if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
-                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
-                    // Don't care about who enables an app.
-                    callingPackage = null;
-                }
-                pkgSetting.setEnabled(newState, userId, callingPackage);
-                // pkgSetting.pkg.mSetEnabled = newState;
+        if (callingUid == Process.SHELL_UID
+                && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
+            // Shell can only change whole packages between ENABLED and DISABLED_USER states
+            // unless it is a test package.
+            int oldState = pkgSetting.getEnabled(userId);
+            if (className == null
+                &&
+                (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                 || oldState == COMPONENT_ENABLED_STATE_DEFAULT
+                 || oldState == COMPONENT_ENABLED_STATE_ENABLED)
+                &&
+                (newState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                 || newState == COMPONENT_ENABLED_STATE_DEFAULT
+                 || newState == COMPONENT_ENABLED_STATE_ENABLED)) {
+                // ok
             } else {
-                // We're dealing with a component level state change
-                // First, verify that this is a valid class name.
-                PackageParser.Package pkg = pkgSetting.pkg;
-                if (pkg == null || !pkg.hasComponentClassName(className)) {
-                    if (pkg != null &&
-                            pkg.applicationInfo.targetSdkVersion >=
-                                    Build.VERSION_CODES.JELLY_BEAN) {
-                        throw new IllegalArgumentException("Component class " + className
-                                + " does not exist in " + packageName);
-                    } else {
-                        Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
-                                + className + " does not exist in " + packageName);
-                    }
-                }
-                switch (newState) {
-                case COMPONENT_ENABLED_STATE_ENABLED:
-                    if (!pkgSetting.enableComponentLPw(className, userId)) {
-                        return;
-                    }
-                    break;
-                case COMPONENT_ENABLED_STATE_DISABLED:
-                    if (!pkgSetting.disableComponentLPw(className, userId)) {
-                        return;
-                    }
-                    break;
-                case COMPONENT_ENABLED_STATE_DEFAULT:
-                    if (!pkgSetting.restoreComponentLPw(className, userId)) {
-                        return;
-                    }
-                    break;
-                default:
-                    Slog.e(TAG, "Invalid new component state: " + newState);
+                throw new SecurityException(
+                        "Shell cannot change component state for " + packageName + "/"
+                        + className + " to " + newState);
+            }
+        }
+        if (className == null) {
+            // We're dealing with an application/package level state change
+            if (pkgSetting.getEnabled(userId) == newState) {
+                // Nothing to do
+                return;
+            }
+            // If we're enabling a system stub, there's a little more work to do.
+            // Prior to enabling the package, we need to decompress the APK(s) to the
+            // data partition and then replace the version on the system partition.
+            final PackageParser.Package deletedPkg = pkgSetting.pkg;
+            final boolean isSystemStub = deletedPkg.isStub
+                    && deletedPkg.isSystemApp();
+            if (isSystemStub
+                    && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                            || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
+                final File codePath = decompressPackage(deletedPkg);
+                if (codePath == null) {
+                    Slog.e(TAG, "couldn't decompress pkg: " + pkgSetting.name);
                     return;
                 }
+                // TODO remove direct parsing of the package object during internal cleanup
+                // of scan package
+                // We need to call parse directly here for no other reason than we need
+                // the new package in order to disable the old one [we use the information
+                // for some internal optimization to optionally create a new package setting
+                // object on replace]. However, we can't get the package from the scan
+                // because the scan modifies live structures and we need to remove the
+                // old [system] package from the system before a scan can be attempted.
+                // Once scan is indempotent we can remove this parse and use the package
+                // object we scanned, prior to adding it to package settings.
+                final PackageParser pp = new PackageParser();
+                pp.setSeparateProcesses(mSeparateProcesses);
+                pp.setDisplayMetrics(mMetrics);
+                pp.setCallback(mPackageParserCallback);
+                final PackageParser.Package tmpPkg;
+                try {
+                    final int parseFlags = mDefParseFlags
+                            | PackageParser.PARSE_MUST_BE_APK
+                            | PackageParser.PARSE_IS_SYSTEM
+                            | PackageParser.PARSE_IS_SYSTEM_DIR;
+                    tmpPkg = pp.parsePackage(codePath, parseFlags);
+                } catch (PackageParserException e) {
+                    Slog.w(TAG, "Failed to parse compressed system package:" + pkgSetting.name, e);
+                    return;
+                }
+                synchronized (mInstallLock) {
+                    // Disable the stub and remove any package entries
+                    removePackageLI(deletedPkg, true);
+                    synchronized (mPackages) {
+                        disableSystemPackageLPw(deletedPkg, tmpPkg);
+                    }
+                    final PackageParser.Package newPkg;
+                    try (PackageFreezer freezer =
+                            freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
+                        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+                                | PackageParser.PARSE_ENFORCE_CODE;
+                        newPkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/,
+                                0 /*currentTime*/, null /*user*/);
+                        prepareAppDataAfterInstallLIF(newPkg);
+                        synchronized (mPackages) {
+                            try {
+                                updateSharedLibrariesLPr(newPkg, null);
+                            } catch (PackageManagerException e) {
+                                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+                            }
+                            updatePermissionsLPw(newPkg.packageName, newPkg,
+                                    UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
+                            mSettings.writeLPr();
+                        }
+                    } catch (PackageManagerException e) {
+                        // Whoops! Something went wrong; try to roll back to the stub
+                        Slog.w(TAG, "Failed to install compressed system package:"
+                                + pkgSetting.name, e);
+                        // Remove the failed install
+                        removeCodePathLI(codePath);
+
+                        // Install the system package
+                        try (PackageFreezer freezer =
+                                freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
+                            synchronized (mPackages) {
+                                // NOTE: The system package always needs to be enabled; even
+                                // if it's for a compressed stub. If we don't, installing the
+                                // system package fails during scan [scanning checks the disabled
+                                // packages]. We will reverse this later, after we've "installed"
+                                // the stub.
+                                // This leaves us in a fragile state; the stub should never be
+                                // enabled, so, cross your fingers and hope nothing goes wrong
+                                // until we can disable the package later.
+                                enableSystemPackageLPw(deletedPkg);
+                            }
+                            installPackageFromSystemLIF(new File(deletedPkg.codePath),
+                                    false /*isPrivileged*/, null /*allUserHandles*/,
+                                    null /*origUserHandles*/, null /*origPermissionsState*/,
+                                    true /*writeSettings*/);
+                        } catch (PackageManagerException pme) {
+                            Slog.w(TAG, "Failed to restore system package:"
+                                    + deletedPkg.packageName, pme);
+                        } finally {
+                            synchronized (mPackages) {
+                                mSettings.disableSystemPackageLPw(
+                                        deletedPkg.packageName, true /*replaced*/);
+                                mSettings.writeLPr();
+                            }
+                        }
+                        return;
+                    }
+                    clearAppDataLIF(newPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
+                            | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+                    clearAppProfilesLIF(newPkg, UserHandle.USER_ALL);
+                    mDexManager.notifyPackageUpdated(newPkg.packageName,
+                            newPkg.baseCodePath, newPkg.splitCodePaths);
+                }
             }
+            if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+                // Don't care about who enables an app.
+                callingPackage = null;
+            }
+            pkgSetting.setEnabled(newState, userId, callingPackage);
+        } else {
+            // We're dealing with a component level state change
+            // First, verify that this is a valid class name.
+            PackageParser.Package pkg = pkgSetting.pkg;
+            if (pkg == null || !pkg.hasComponentClassName(className)) {
+                if (pkg != null &&
+                        pkg.applicationInfo.targetSdkVersion >=
+                                Build.VERSION_CODES.JELLY_BEAN) {
+                    throw new IllegalArgumentException("Component class " + className
+                            + " does not exist in " + packageName);
+                } else {
+                    Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
+                            + className + " does not exist in " + packageName);
+                }
+            }
+            switch (newState) {
+            case COMPONENT_ENABLED_STATE_ENABLED:
+                if (!pkgSetting.enableComponentLPw(className, userId)) {
+                    return;
+                }
+                break;
+            case COMPONENT_ENABLED_STATE_DISABLED:
+                if (!pkgSetting.disableComponentLPw(className, userId)) {
+                    return;
+                }
+                break;
+            case COMPONENT_ENABLED_STATE_DEFAULT:
+                if (!pkgSetting.restoreComponentLPw(className, userId)) {
+                    return;
+                }
+                break;
+            default:
+                Slog.e(TAG, "Invalid new component state: " + newState);
+                return;
+            }
+        }
+        synchronized (mPackages) {
             scheduleWritePackageRestrictionsLocked(userId);
             updateSequenceNumberLP(pkgSetting, new int[] { userId });
             final long callingId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d99408f..56835f6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4867,7 +4867,7 @@
             pw.print(" enabled=");
             pw.print(ps.getEnabled(user.id));
             pw.print(" instant=");
-            pw.println(ps.getInstantApp(user.id));
+            pw.print(ps.getInstantApp(user.id));
             pw.print(" virtual=");
             pw.println(ps.getVirtulalPreload(user.id));
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ae78d7c..3c11a53 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7466,10 +7466,12 @@
         }
     }
 
+    // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
     private void updateDreamingSleepToken(boolean acquire) {
         if (acquire) {
             if (mDreamingSleepToken == null) {
-                mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken("Dream");
+                mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken(
+                        "Dream", Display.DEFAULT_DISPLAY);
             }
         } else {
             if (mDreamingSleepToken != null) {
@@ -7479,10 +7481,12 @@
         }
     }
 
+    // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
     private void updateScreenOffSleepToken(boolean acquire) {
         if (acquire) {
             if (mScreenOffSleepToken == null) {
-                mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken("ScreenOff");
+                mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken(
+                        "ScreenOff", Display.DEFAULT_DISPLAY);
             }
         } else {
             if (mScreenOffSleepToken != null) {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index d1a5953..63900e0 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -715,6 +715,7 @@
      * @param reason reason for reboot/shutdown
      */
     public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
+        SHUTDOWN_TIMINGS_LOG.traceEnd(); // SystemServerShutdown
         if (reboot) {
             Log.i(TAG, "Rebooting, reason: " + reason);
             PowerManagerService.lowLevelReboot(reason);
@@ -736,7 +737,6 @@
             } catch (InterruptedException unused) {
             }
         }
-        SHUTDOWN_TIMINGS_LOG.traceEnd(); // SystemServerShutdown
         // Shutdown power
         Log.i(TAG, "Performing low-level shutdown...");
         PowerManagerService.lowLevelShutdown(reason);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 2b3901b..c2edc04 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,8 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -358,7 +358,7 @@
 
     // This must be called while inside a transaction.
     boolean stepAnimationLocked(long currentTime) {
-        if (mService.okToAnimate()) {
+        if (mAppToken.okToAnimate()) {
             // We will run animations as long as the display isn't frozen.
 
             if (animation == sDummyAnimation) {
@@ -423,8 +423,8 @@
 
         if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
                 + ": reportedVisible=" + mAppToken.reportedVisible
-                + " okToDisplay=" + mService.okToDisplay()
-                + " okToAnimate=" + mService.okToAnimate()
+                + " okToDisplay=" + mAppToken.okToDisplay()
+                + " okToAnimate=" + mAppToken.okToAnimate()
                 + " startingDisplayed=" + mAppToken.startingDisplayed);
 
         transformation.clear();
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index e9696d2..f142ff6 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 
 import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
@@ -401,7 +402,7 @@
 
             // If we are preparing an app transition, then delay changing
             // the visibility of this token until we execute that transition.
-            if (mService.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
+            if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
                 // A dummy animation is a placeholder animation which informs others that an
                 // animation is going on (in this case an application transition). If the animation
                 // was transferred from another application/animator, no dummy animator should be
@@ -478,7 +479,7 @@
 
             // If the display is frozen, we won't do anything until the actual window is
             // displayed so there is no reason to put in the starting window.
-            if (!mService.okToDisplay()) {
+            if (!mContainer.okToDisplay()) {
                 return false;
             }
 
@@ -631,9 +632,12 @@
                 mContainer.startingSurface = null;
                 mContainer.startingWindow = null;
                 mContainer.startingDisplayed = false;
-                if (surface == null && DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
-                            + "remove");
+                if (surface == null) {
+                    if (DEBUG_STARTING_WINDOW) {
+                        Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
+                                + "remove");
+                    }
+                    return;
                 }
             } else {
                 if (DEBUG_STARTING_WINDOW) {
@@ -699,16 +703,17 @@
 
     public void startFreezingScreen(int configChanges) {
         synchronized(mWindowMap) {
-            if (configChanges == 0 && mService.okToDisplay()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
-                return;
-            }
-
             if (mContainer == null) {
                 Slog.w(TAG_WM,
                         "Attempted to freeze screen with non-existing app token: " + mContainer);
                 return;
             }
+
+            if (configChanges == 0 && mContainer.okToDisplay()) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+                return;
+            }
+
             mContainer.startFreezingScreen();
         }
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 46049f59..f4ac961 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -63,6 +63,7 @@
 import android.view.IApplicationToken;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.util.ToBooleanFunction;
@@ -471,6 +472,20 @@
         return delayed;
     }
 
+    /**
+     * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
+     *         true.
+     */
+    WindowState getTopFullscreenWindow() {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            if (win != null && win.mAttrs.isFullscreen()) {
+                return win;
+            }
+        }
+        return null;
+    }
+
     WindowState findMainWindow() {
         WindowState candidate = null;
         int j = mChildren.size();
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 7414928..6f9e45a 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -290,7 +290,7 @@
             state.dimLayer.setLayer(dimLayer);
         }
         if (state.dimLayer.isAnimating()) {
-            if (!mDisplayContent.mService.okToAnimate()) {
+            if (!mDisplayContent.okToAnimate()) {
                 // Jump to the end of the animation.
                 state.dimLayer.show();
             } else {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5bc4a6b..f0a375b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3204,6 +3204,19 @@
         mService.requestTraversal();
     }
 
+    boolean okToDisplay() {
+        if (mDisplayId == DEFAULT_DISPLAY) {
+            return !mService.mDisplayFrozen
+                    && mService.mDisplayEnabled && mService.mPolicy.isScreenOn();
+        }
+        return mDisplayInfo.state == Display.STATE_ON;
+    }
+
+    boolean okToAnimate() {
+        return okToDisplay() &&
+                (mDisplayId != DEFAULT_DISPLAY || mService.mPolicy.okToAnimate());
+    }
+
     static final class TaskForResizePointSearchResult {
         boolean searchDone;
         Task taskForResize;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 940ad33..bc7f330 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -102,6 +102,11 @@
      */
     private final boolean mIsRunningOnIoT;
 
+    /**
+     * Flag indicating whether we are running on an Android Wear device.
+     */
+    private final boolean mIsRunningOnWear;
+
     TaskSnapshotController(WindowManagerService service) {
         mService = service;
         mCache = new TaskSnapshotCache(mService, mLoader);
@@ -109,6 +114,8 @@
                 PackageManager.FEATURE_LEANBACK);
         mIsRunningOnIoT = mService.mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_EMBEDDED);
+        mIsRunningOnWear = mService.mContext.getPackageManager().hasSystemFeature(
+            PackageManager.FEATURE_WATCH);
     }
 
     void systemReady() {
@@ -204,7 +211,7 @@
         }
         final GraphicBuffer buffer = top.mDisplayContent.screenshotApplicationsToBuffer(top.token,
                 -1, -1, false, 1.0f, false, true);
-        if (buffer == null) {
+        if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
             return null;
         }
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
@@ -213,8 +220,7 @@
     }
 
     private boolean shouldDisableSnapshots() {
-        return !ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()
-                || mIsRunningOnTv || mIsRunningOnIoT;
+        return !ENABLE_TASK_SNAPSHOTS || mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
     }
 
     private Rect minRect(Rect rect1, Rect rect2) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 1bece69..0610b94 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -162,7 +162,7 @@
                         + task);
                 return null;
             }
-            final WindowState topFullscreenWindow = topFullscreenToken.findMainWindow();
+            final WindowState topFullscreenWindow = topFullscreenToken.getTopFullscreenWindow();
             if (mainWindow == null || topFullscreenWindow == null) {
                 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
                         + token);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5c664c2..e7f3de0b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2347,7 +2347,7 @@
         // artifacts when we unfreeze the display if some different animation
         // is running.
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
-        if (okToAnimate()) {
+        if (atoken.okToAnimate()) {
             final DisplayContent displayContent = atoken.getTask().getDisplayContent();
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             final int width = displayInfo.appWidth;
@@ -2425,14 +2425,6 @@
         return false;
     }
 
-    boolean okToDisplay() {
-        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn();
-    }
-
-    boolean okToAnimate() {
-        return okToDisplay() && mPolicy.okToAnimate();
-    }
-
     @Override
     public void addWindowToken(IBinder binder, int type, int displayId) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
@@ -2699,7 +2691,9 @@
         synchronized(mWindowMap) {
             boolean prepared = mAppTransition.prepareAppTransitionLocked(transit, alwaysKeepCurrent,
                     flags, forceOverride);
-            if (prepared && okToAnimate()) {
+            // TODO (multidisplay): associate app transitions with displays
+            final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+            if (prepared && dc != null && dc.okToAnimate()) {
                 mSkipAppTransitionAnimation = false;
             }
         }
@@ -5817,7 +5811,10 @@
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
         // orientation.
-        if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+        // TODO (multidisplay): Support screen freezing on secondary displays.
+        final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+        if ((dc == null || !dc.okToDisplay())
+                && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
             w.setOrientationChanging(true);
             w.mLastFreezeDuration = 0;
@@ -6033,7 +6030,7 @@
             return;
         }
 
-        if (!displayContent.isReady() || !mPolicy.isScreenOn() || !okToAnimate()) {
+        if (!displayContent.isReady() || !mPolicy.isScreenOn() || !displayContent.okToAnimate()) {
             // No need to freeze the screen before the display is ready,  if the screen is off,
             // or we can't currently animate.
             return;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2b258c9..da739ac 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1711,7 +1711,7 @@
         final boolean adjustedForMinimizedDockOrIme = task != null
                 && (task.mStack.isAdjustedForMinimizedDockedStack()
                 || task.mStack.isAdjustedForIme());
-        if (mService.okToAnimate()
+        if (mToken.okToAnimate()
                 && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                 && !isDragResizing() && !adjustedForMinimizedDockOrIme
                 && (task == null || getTask().mStack.hasMovementAnimations())
@@ -1880,7 +1880,7 @@
         // First, see if we need to run an animation. If we do, we have to hold off on removing the
         // window until the animation is done. If the display is frozen, just remove immediately,
         // since the animation wouldn't be seen.
-        if (mHasSurface && mService.okToAnimate()) {
+        if (mHasSurface && mToken.okToAnimate()) {
             if (mWillReplaceWindow) {
                 // This window is going to be replaced. We need to keep it around until the new one
                 // gets added, then we will get rid of this one.
@@ -2315,7 +2315,7 @@
             mLayoutNeeded = true;
         }
 
-        if (isDrawnLw() && mService.okToAnimate()) {
+        if (isDrawnLw() && mToken.okToAnimate()) {
             mWinAnimator.applyEnterAnimationLocked();
         }
     }
@@ -2471,7 +2471,7 @@
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
                     + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
-            if (!mService.okToAnimate()) {
+            if (!mToken.okToAnimate()) {
                 doAnimation = false;
             } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
                 // Check for the case where we are currently visible and
@@ -2501,7 +2501,7 @@
 
     boolean hideLw(boolean doAnimation, boolean requestAnim) {
         if (doAnimation) {
-            if (!mService.okToAnimate()) {
+            if (!mToken.okToAnimate()) {
                 doAnimation = false;
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 86265c29..053ee97 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -369,7 +369,7 @@
         // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
         mWasAnimating = mAnimating;
         final DisplayContent displayContent = mWin.getDisplayContent();
-        if (displayContent != null && mService.okToAnimate()) {
+        if (mWin.mToken.okToAnimate()) {
             // We will run animations as long as the display isn't frozen.
 
             if (mWin.isDrawnLw() && mAnimation != null) {
@@ -1812,7 +1812,7 @@
         // artifacts when we unfreeze the display if some different animation
         // is running.
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
-        if (mService.okToAnimate()) {
+        if (mWin.mToken.okToAnimate()) {
             int anim = mPolicy.selectAnimationLw(mWin, transit);
             int attr = -1;
             Animation a = null;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e3033c9..48d1618 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -288,4 +288,12 @@
     String getName() {
         return toString();
     }
+
+    boolean okToDisplay() {
+        return mDisplayContent != null && mDisplayContent.okToDisplay();
+    }
+
+    boolean okToAnimate() {
+        return mDisplayContent != null && mDisplayContent.okToAnimate();
+    }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 801479b..65bf330 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -46,6 +46,7 @@
 import android.app.NotificationManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.net.Uri;
@@ -78,6 +79,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -127,6 +129,8 @@
         when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
         when(mContext.getResources()).thenReturn(
                 InstrumentationRegistry.getContext().getResources());
+        when(mContext.getContentResolver()).thenReturn(
+                InstrumentationRegistry.getContext().getContentResolver());
         when(mContext.getPackageManager()).thenReturn(mPm);
         when(mContext.getApplicationInfo()).thenReturn(legacy);
         // most tests assume badging is enabled
@@ -1366,4 +1370,22 @@
         assertFalse(mHelper.badgingEnabled(USER));
         assertTrue(mHelper.badgingEnabled(USER2));
     }
+
+    @Test
+    public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
+        String newLabel = "bananas!";
+        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false);
+        assertFalse(newLabel.equals(defaultChannel.getName()));
+
+        Resources res = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(res);
+        when(res.getString(com.android.internal.R.string.default_notification_channel_label))
+                .thenReturn(newLabel);
+
+        mHelper.onLocaleChanged(mContext, USER.getIdentifier());
+
+        assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
+    }
 }
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 507b483..19396d4 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -29,7 +29,8 @@
 
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
 
-LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
+LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl \
+    aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
 
 LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test
 
@@ -61,3 +62,5 @@
 LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
 
 include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 63f3b75..6a9983e 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Runs Frameworks Services Tests.">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
+        <option name="test-file-name" value="ConnTestApp.apk" />
     </target_preparer>
 
     <option name="test-suite-tag" value="apct" />
diff --git a/services/tests/servicestests/aidl/Android.mk b/services/tests/servicestests/aidl/Android.mk
index 0c9b839..166da1d 100644
--- a/services/tests/servicestests/aidl/Android.mk
+++ b/services/tests/servicestests/aidl/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := \
-        com/android/servicestests/aidl/INetworkStateObserver.aidl
+        com/android/servicestests/aidl/INetworkStateObserver.aidl \
+        com/android/servicestests/aidl/ICmdReceiverService.aidl
 LOCAL_MODULE := servicestests-aidl
 include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl b/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
new file mode 100644
index 0000000..d964504
--- /dev/null
+++ b/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.servicestests.aidl;
+
+interface ICmdReceiverService {
+    void finishActivity();
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/res/raw/conntestapp b/services/tests/servicestests/res/raw/conntestapp
deleted file mode 100644
index e993164..0000000
--- a/services/tests/servicestests/res/raw/conntestapp
+++ /dev/null
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 48464e5..ba22159 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -78,7 +78,7 @@
         service.mStackSupervisor.inResumeTopActivity = true;
         testStack.mResumedActivity = activityRecord;
 
-        final boolean waiting = testStack.checkReadyForSleepLocked();
+        final boolean waiting = testStack.goToSleepIfPossible(false);
 
         // Ensure we report not being ready for sleep.
         assertTrue(waiting);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 04b5bde..4ad92c7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -218,6 +218,12 @@
 
             return createTestStack(stackId, createOnTop);
         }
+
+        // Always keep things awake
+        @Override
+        boolean hasAwakeDisplay() {
+            return true;
+        }
     }
 
     private static WindowManagerService prepareMockWindowManager() {
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 5b4c10f..7f48b8e 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -16,48 +16,37 @@
 
 package com.android.server.net;
 
-import static android.util.DebugUtils.valueToString;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import com.android.frameworks.servicestests.R;
+import com.android.servicestests.aidl.ICmdReceiverService;
 import com.android.servicestests.aidl.INetworkStateObserver;
 
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.PackageInstaller;
+import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Bundle;
-import android.os.RemoteException;
+import android.os.IBinder;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.util.Log;
 
-import libcore.io.IoUtils;
-
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -76,62 +65,118 @@
  * Run: adb shell am instrument -e class com.android.server.net.ConnOnActivityStartTest -w \
  *     com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
-@Ignore
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class ConnOnActivityStartTest {
     private static final String TAG = ConnOnActivityStartTest.class.getSimpleName();
 
-    private static final String ACTION_INSTALL_COMPLETE = "com.android.server.net.INSTALL_COMPLETE";
-
-    private static final String TEST_APP_URI =
-            "android.resource://com.android.frameworks.servicestests/raw/conntestapp";
     private static final String TEST_PKG = "com.android.servicestests.apps.conntestapp";
     private static final String TEST_ACTIVITY_CLASS = TEST_PKG + ".ConnTestActivity";
-
-    private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
+    private static final String TEST_SERVICE_CLASS = TEST_PKG + ".CmdReceiverService";
 
     private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
 
     private static final long BATTERY_OFF_TIMEOUT_MS = 2000; // 2 sec
     private static final long BATTERY_OFF_CHECK_INTERVAL_MS = 200; // 0.2 sec
 
-    private static final long WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
-
     private static final long NETWORK_CHECK_TIMEOUT_MS = 4000; // 4 sec
 
     private static final long SCREEN_ON_DELAY_MS = 500; // 0.5 sec
 
+    private static final long BIND_SERVICE_TIMEOUT_SEC = 4;
+
     private static final int REPEAT_TEST_COUNT = 5;
 
+    private static final String KEY_PAROLE_DURATION = "parole_duration";
+    private static final String DESIRED_PAROLE_DURATION = "0";
+
     private static Context mContext;
     private static UiDevice mUiDevice;
     private static int mTestPkgUid;
     private static BatteryManager mBatteryManager;
 
+    private static boolean mAppIdleConstsUpdated;
+    private static String mOriginalAppIdleConsts;
+
+    private static ServiceConnection mServiceConnection;
+    private static ICmdReceiverService mCmdReceiverService;
+
     @BeforeClass
     public static void setUpOnce() throws Exception {
         mContext = InstrumentationRegistry.getContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
-        installAppAndAssertInstalled();
+        setDesiredParoleDuration();
         mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
         mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
 
         mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
+        bindService();
     }
 
     @AfterClass
     public static void tearDownOnce() {
-        mContext.getPackageManager().deletePackage(TEST_PKG,
-                new IPackageDeleteObserver.Stub() {
-                    @Override
-                    public void packageDeleted(String packageName, int returnCode)
-                            throws RemoteException {
-                        Log.e(TAG, packageName + " deleted, returnCode: " + returnCode);
-                    }
-                }, 0);
+        if (mAppIdleConstsUpdated) {
+            Settings.Global.putString(mContext.getContentResolver(),
+                    Settings.Global.APP_IDLE_CONSTANTS, mOriginalAppIdleConsts);
+        }
+        unbindService();
+    }
+
+    private static void bindService() throws Exception {
+        final CountDownLatch bindLatch = new CountDownLatch(1);
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                Log.i(TAG, "Service connected");
+                mCmdReceiverService = ICmdReceiverService.Stub.asInterface(service);
+                bindLatch.countDown();
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                Log.i(TAG, "Service disconnected");
+            }
+        };
+        final Intent intent = new Intent()
+                .setComponent(new ComponentName(TEST_PKG, TEST_SERVICE_CLASS));
+        // Needs to use BIND_ALLOW_OOM_MANAGEMENT and BIND_NOT_FOREGROUND so that the test app
+        // does not run in the same process state as this app.
+        mContext.bindService(intent, mServiceConnection,
+                Context.BIND_AUTO_CREATE
+                        | Context.BIND_ALLOW_OOM_MANAGEMENT
+                        | Context.BIND_NOT_FOREGROUND);
+        if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            fail("Timed out waiting for the service to bind in " + mTestPkgUid);
+        }
+    }
+
+    private static void unbindService() {
+        if (mCmdReceiverService != null) {
+            mContext.unbindService(mServiceConnection);
+        }
+    }
+
+    private static void setDesiredParoleDuration() {
+        mOriginalAppIdleConsts = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.APP_IDLE_CONSTANTS);
+        String newAppIdleConstants;
+        final String newConstant = KEY_PAROLE_DURATION + "=" + DESIRED_PAROLE_DURATION;
+        if (mOriginalAppIdleConsts == null || "null".equals(mOriginalAppIdleConsts)) {
+            // app_idle_constants is initially empty, so just assign the desired value.
+            newAppIdleConstants = newConstant;
+        } else if (mOriginalAppIdleConsts.contains(KEY_PAROLE_DURATION)) {
+            // app_idle_constants contains parole_duration, so replace it with the desired value.
+            newAppIdleConstants = mOriginalAppIdleConsts.replaceAll(
+                    KEY_PAROLE_DURATION + "=\\d+", newConstant);
+        } else {
+            // app_idle_constants didn't have parole_duration, so append the desired value.
+            newAppIdleConstants = mOriginalAppIdleConsts + "," + newConstant;
+        }
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.APP_IDLE_CONSTANTS, newAppIdleConstants);
+        mAppIdleConstsUpdated = true;
     }
 
     @Test
@@ -174,6 +219,7 @@
             startActivityAndCheckNetworkAccess();
         } finally {
             turnBatteryOn();
+            finishActivity();
             setAppIdle(false);
         }
     }
@@ -195,9 +241,9 @@
                 turnScreenOn();
                 SystemClock.sleep(SCREEN_ON_DELAY_MS);
                 startActivityAndCheckNetworkAccess();
-                Log.d(TAG, testName + " end #" + i);
             } finally {
                 finishActivity();
+                Log.d(TAG, testName + " end #" + i);
             }
         }
     }
@@ -348,74 +394,7 @@
         }
     }
 
-    private void finishActivity() {
-        final Intent finishIntent = new Intent(ACTION_FINISH_ACTIVITY)
-                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mContext.sendBroadcast(finishIntent);
-    }
-    private static void installAppAndAssertInstalled() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final int[] result = {PackageInstaller.STATUS_SUCCESS};
-        final BroadcastReceiver installStatusReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
-                if (!TEST_PKG.equals(pkgName)) {
-                    return;
-                }
-                result[0] = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                        PackageInstaller.STATUS_FAILURE);
-                latch.countDown();
-            }
-        };
-        mContext.registerReceiver(installStatusReceiver, new IntentFilter(ACTION_INSTALL_COMPLETE));
-        try {
-            installApp();
-            if (latch.await(WAIT_FOR_INSTALL_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                if (result[0] != PackageInstaller.STATUS_SUCCESS) {
-                    fail("Couldn't install test app, result: "
-                            + valueToString(PackageInstaller.class, "STATUS_", result[0]));
-                }
-            } else {
-                fail("Timed out waiting for the test app to install");
-            }
-        } finally {
-            mContext.unregisterReceiver(installStatusReceiver);
-        }
-    }
-
-    private static void installApp() throws Exception {
-        final Uri packageUri = Uri.parse(TEST_APP_URI);
-        final InputStream in = mContext.getContentResolver().openInputStream(packageUri);
-
-        final PackageInstaller packageInstaller
-                = mContext.getPackageManager().getPackageInstaller();
-        final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        params.setAppPackageName(TEST_PKG);
-
-        final int sessionId = packageInstaller.createSession(params);
-        final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
-        OutputStream out = null;
-        try {
-            out = session.openWrite(TAG, 0, -1);
-            final byte[] buffer = new byte[65536];
-            int c;
-            while ((c = in.read(buffer)) != -1) {
-                out.write(buffer, 0, c);
-            }
-            session.fsync(out);
-        } finally {
-            IoUtils.closeQuietly(in);
-            IoUtils.closeQuietly(out);
-        }
-        session.commit(createIntentSender(mContext, sessionId));
-    }
-
-    private static IntentSender createIntentSender(Context context, int sessionId) {
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(
-                context, sessionId, new Intent(ACTION_INSTALL_COMPLETE), 0);
-        return pendingIntent.getIntentSender();
+    private void finishActivity() throws Exception {
+        mCmdReceiverService.finishActivity();
     }
 }
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index b09601e..9ad7add 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -97,6 +97,24 @@
     }
 
     @Test
+    public void testGetTopFullscreenWindow() throws Exception {
+        final WindowTestUtils.TestAppWindowToken token =
+                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+
+        assertNull(token.getTopFullscreenWindow());
+
+        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
+        final WindowState window11 = createWindow(null, TYPE_APPLICATION, token, "window11");
+        final WindowState window12 = createWindow(null, TYPE_APPLICATION, token, "window12");
+        assertEquals(window12, token.getTopFullscreenWindow());
+        window12.mAttrs.width = 500;
+        assertEquals(window11, token.getTopFullscreenWindow());
+        window11.mAttrs.width = 500;
+        assertEquals(window1, token.getTopFullscreenWindow());
+        token.removeImmediately();
+    }
+
+    @Test
     public void testLandscapeSeascapeRotationByApp() throws Exception {
         // Some plumbing to get the service ready for rotation updates.
         sWm.mDisplayReady = true;
diff --git a/services/tests/servicestests/test-apps/Android.mk b/services/tests/servicestests/test-apps/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/services/tests/servicestests/test-apps/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
index 030a709..fbfa28a 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
@@ -18,6 +18,8 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
index 6671410..909e9bb 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -24,6 +24,8 @@
     <application>
         <activity android:name=".ConnTestActivity"
                   android:exported="true" />
+        <service android:name=".CmdReceiverService"
+                 android:exported="true" />
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
new file mode 100644
index 0000000..6130f3a
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.servicestests.apps.conntestapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.servicestests.aidl.ICmdReceiverService;
+
+public class CmdReceiverService extends Service {
+    private ICmdReceiverService.Stub mBinder = new ICmdReceiverService.Stub() {
+        @Override
+        public void finishActivity() {
+            ConnTestActivity.finishSelf();
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
index c5c7add..b26cc7fd 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
@@ -30,6 +30,7 @@
 import android.os.ServiceManager;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.servicestests.aidl.INetworkStateObserver;
 
 public class ConnTestActivity extends Activity {
@@ -39,17 +40,26 @@
     private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
     private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
 
+    private static final Object INSTANCE_LOCK = new Object();
+    @GuardedBy("instanceLock")
+    private static Activity sInstance;
+
     private BroadcastReceiver finishCommandReceiver = null;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        synchronized (INSTANCE_LOCK) {
+            sInstance = this;
+        }
+        Log.i(TAG, "onCreate called");
 
         notifyNetworkStateObserver();
 
         finishCommandReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                Log.i(TAG, "finish command received");
                 ConnTestActivity.this.finish();
             }
         };
@@ -57,13 +67,37 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        Log.i(TAG, "onResume called");
+    }
+
+    @Override
     public void onStop() {
+        Log.i(TAG, "onStop called");
         if (finishCommandReceiver != null) {
             unregisterReceiver(finishCommandReceiver);
         }
         super.onStop();
     }
 
+    @Override
+    public void finish() {
+        synchronized (INSTANCE_LOCK) {
+            sInstance = null;
+        }
+        Log.i(TAG, "finish called");
+        super.finish();
+    }
+
+    public static void finishSelf() {
+        synchronized (INSTANCE_LOCK) {
+            if (sInstance != null) {
+                sInstance.finish();
+            }
+        }
+    }
+
     private void notifyNetworkStateObserver() {
         if (getIntent() == null) {
             return;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c1289d3..e13bd61 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1089,12 +1089,17 @@
          * @return A string containing text sent by the remote user, or {@code null} if the
          * conversation has been terminated or if there was an error while reading.
          */
-        public String read() throws IOException {
-            int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
-            if (numRead < 0) {
+        public String read() {
+            try {
+                int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
+            } catch (IOException e) {
+                Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
                 return null;
             }
-            return new String(mReadBuffer, 0, numRead);
         }
 
         /**
@@ -1105,7 +1110,11 @@
          */
         public String readImmediately() throws IOException {
             if (mReceiveStream.ready()) {
-                return read();
+                int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
             } else {
                 return null;
             }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3a34d8f..735f09b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -567,20 +567,27 @@
             "carrier_data_call_retry_config_strings";
 
     /**
-     * Delay between trying APN from the pool
+     * Delay in milliseconds between trying APN from the pool
      * @hide
      */
     public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
             "carrier_data_call_apn_delay_default_long";
 
     /**
-     * Faster delay between trying APN from the pool
+     * Faster delay in milliseconds between trying APN from the pool
      * @hide
      */
     public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
             "carrier_data_call_apn_delay_faster_long";
 
     /**
+     * Delay in milliseconds for retrying APN after disconnect
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG =
+            "carrier_data_call_apn_retry_after_disconnect_long";
+
+    /**
      * Data call setup permanent failure causes by the carrier
      */
     public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -768,7 +775,6 @@
      * Determines whether High Definition audio property is displayed in the dialer UI.
      * If {@code false}, remove the HD audio property from the connection so that HD audio related
      * UI is not displayed. If {@code true}, keep HD audio property as it is configured.
-     * @hide
      */
     public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL =
             "display_hd_audio_property_bool";
@@ -1167,8 +1173,6 @@
     /** @hide */
     public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
     /** @hide */
-    public static final int IMSI_ENCRYPTION_DAYS_TIME_DISABLED = -1;
-    /** @hide */
     public static final int CDMA_ROAMING_MODE_ANY = 2;
     /**
      * Boolean indicating if support is provided for directly dialing FDN number from FDN list.
@@ -1527,14 +1531,15 @@
     public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
 
     /**
-     * Time in days, after which the key will expire, and a new key will need to be downloaded.
-     * default value is {@link IMSI_ENCRYPTION_DAYS_TIME_DISABLED}, and indicates that IMSI
-     * encryption is not enabled by default for a carrier. Value of 0 indicates that the key
-     * does not expire.
+     * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
+     * 0 indicates that neither EPDG or WLAN is enabled.
+     * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled.
+     * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled.
+     * 3 indicates that both are enabled.
      * @hide
      */
-    public static final String IMSI_KEY_EXPIRATION_DAYS_TIME_INT =
-            "imsi_key_expiration_days_time_int";
+    public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
+
 
     /**
      * Key identifying if the CDMA Caller ID presentation and suppression MMI codes
@@ -1646,6 +1651,7 @@
                 "others:max_retries=3, 5000, 5000, 5000"});
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
+        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 10000);
         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
         sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
         sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
@@ -1807,7 +1813,7 @@
         sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
         sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
-        sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED);
+        sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
         sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
         sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
                 false);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5fb83ab..e448fb2 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -795,34 +795,57 @@
         return rtString;
     }
 
+    /**
+     * Convert RIL Service State to String
+     *
+     * @param serviceState
+     * @return String representation of the ServiceState
+     *
+     * @hide
+     */
+    public static String rilServiceStateToString(int serviceState) {
+        switch(serviceState) {
+            case STATE_IN_SERVICE:
+                return "IN_SERVICE";
+            case STATE_OUT_OF_SERVICE:
+                return "OUT_OF_SERVICE";
+            case STATE_EMERGENCY_ONLY:
+                return "EMERGENCY_ONLY";
+            case STATE_POWER_OFF:
+                return "POWER_OFF";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     @Override
     public String toString() {
-        String radioTechnology = rilRadioTechnologyToString(mRilVoiceRadioTechnology);
-        String dataRadioTechnology = rilRadioTechnologyToString(mRilDataRadioTechnology);
-
-        return (mVoiceRegState + " " + mDataRegState
-                + " "
-                + "voice " + getRoamingLogString(mVoiceRoamingType)
-                + " "
-                + "data " + getRoamingLogString(mDataRoamingType)
-                + " " + mVoiceOperatorAlphaLong
-                + " " + mVoiceOperatorAlphaShort
-                + " " + mVoiceOperatorNumeric
-                + " " + mDataOperatorAlphaLong
-                + " " + mDataOperatorAlphaShort
-                + " " + mDataOperatorNumeric
-                + " " + (mIsManualNetworkSelection ? "(manual)" : "")
-                + " " + radioTechnology
-                + " " + dataRadioTechnology
-                + " " + (mCssIndicator ? "CSS supported" : "CSS not supported")
-                + " " + mNetworkId
-                + " " + mSystemId
-                + " RoamInd=" + mCdmaRoamingIndicator
-                + " DefRoamInd=" + mCdmaDefaultRoamingIndicator
-                + " EmergOnly=" + mIsEmergencyOnly
-                + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration
-                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation
-                + " mLteEarfcnRsrpBoost=" + mLteEarfcnRsrpBoost);
+        return new StringBuilder().append("{mVoiceRegState=").append(mVoiceRegState)
+            .append("(" + rilServiceStateToString(mVoiceRegState) + ")")
+            .append(", mDataRegState=").append(mDataRegState)
+            .append("(" + rilServiceStateToString(mDataRegState) + ")")
+            .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
+            .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
+            .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
+            .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
+            .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
+            .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
+            .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
+            .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
+            .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")")
+            .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")")
+            .append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported")
+            .append(", mNetworkId=").append(mNetworkId)
+            .append(", mSystemId=").append(mSystemId)
+            .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
+            .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
+            .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
+            .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
+            .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+            .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
+            .append("}").toString();
     }
 
     private void setNullState(int state) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6a9d00e..2c02869 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -137,7 +137,7 @@
 
 
     /** @hide */
-    static public final int KEY_TYPE_EPDDG = 1;
+    static public final int KEY_TYPE_EPDG = 1;
 
     /** @hide */
     static public final int KEY_TYPE_WLAN = 2;
@@ -2373,33 +2373,75 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      * @param keyType whether the key is being used for wlan or epdg. Valid key types are
-     *        {@link TelephonyManager#KEY_TYPE_EPDDG} or
+     *        {@link TelephonyManager#KEY_TYPE_EPDG} or
      *        {@link TelephonyManager#KEY_TYPE_WLAN}.
      * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
      *         IMSI and IMPI. This includes the public key and the key identifier. This information
-     *         will be stored in the device keystore.
+     *         will be stored in the device keystore. The system will return a null when no key was
+     *         found, and the carrier does not require a key. The system will throw the following
+     *         exceptions:
+     *         1. IllegalArgumentException when an invalid key is sent.
+     *         2. RuntimeException if the key is required but not found; and also if there was an
+     *         internal exception.
      * @hide
      */
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
-            if (info == null) return null;
-            int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
-            if (keyType != KEY_TYPE_EPDDG && keyType != KEY_TYPE_WLAN) {
-                throw new IllegalArgumentException("Invalid key type");
+            if (info == null) {
+                throw new RuntimeException("IMSI error: Subscriber Info is null");
             }
-            return info.getCarrierInfoForImsiEncryption(subId, keyType,
-                    mContext.getOpPackageName());
+            int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
+            if (keyType != KEY_TYPE_EPDG && keyType != KEY_TYPE_WLAN) {
+                throw new IllegalArgumentException("IMSI error: Invalid key type");
+            }
+            ImsiEncryptionInfo imsiEncryptionInfo = info.getCarrierInfoForImsiEncryption(
+                    subId, keyType, mContext.getOpPackageName());
+            if (imsiEncryptionInfo  == null
+                    && isImsiEncryptionRequired(subId, keyType)) {
+                Rlog.e(TAG, "IMSI error: key is required but not found");
+                throw new RuntimeException("IMSI error: key is required but not found");
+            }
+            return imsiEncryptionInfo;
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException", ex);
-            return null;
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
+            throw new RuntimeException("IMSI error: Remote Exception");
         } catch (NullPointerException ex) {
             // This could happen before phone restarts due to crashing
-            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException", ex);
-            return null;
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
+            throw new RuntimeException("IMSI error: Null Pointer exception");
         }
     }
 
+   /**
+     * @param keyAvailability bitmask that defines the availabilty of keys for a type.
+     * @param keyType the key type which is being checked. (WLAN, EPDG)
+     * @return true if the digit at position keyType is 1, else false.
+     * @hide
+     */
+    private static boolean isKeyEnabled(int keyAvailability, int keyType) {
+        int returnValue = (keyAvailability >> (keyType - 1)) & 1;
+        return (returnValue == 1) ? true : false;
+    }
+
+    /**
+     * If Carrier requires Imsi to be encrypted.
+     * @hide
+     */
+    private boolean isImsiEncryptionRequired(int subId, int keyType) {
+        CarrierConfigManager configManager =
+                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager == null) {
+            return false;
+        }
+        PersistableBundle pb = configManager.getConfigForSubId(subId);
+        if (pb == null) {
+            return false;
+        }
+        int keyAvailability = pb.getInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT);
+        return isKeyEnabled(keyAvailability, keyType);
+    }
+
     /**
      * Sets the Carrier specific information that will be used to encrypt the IMSI and IMPI.
      * This includes the public key and the key identifier. This information will be stored in the
@@ -6695,11 +6737,13 @@
      * Get aggregated video call data usage since boot.
      * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required.
      *
-     * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
+     * @param how one of the NetworkStats.STATS_PER_* constants depending on whether the request is
+     * for data usage per uid or overall usage.
      * @return Snapshot of video call data usage
      * @hide
      */
-    public NetworkStats getVtDataUsage(boolean perUidStats) {
+    public NetworkStats getVtDataUsage(int how) {
+        boolean perUidStats = (how == NetworkStats.STATS_PER_UID);
         try {
             ITelephony service = getITelephony();
             if (service != null) {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 8304d84..a13af5f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -154,6 +154,14 @@
             "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT";
 
     /**
+     * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for
+     * whether the user choses to use eUICC to set up network in SUW.
+     * @hide
+     */
+    public static final String EXTRA_FORCE_PROVISION =
+            "android.telephony.euicc.extra.FORCE_PROVISION";
+
+    /**
      * Optional meta-data attribute for a carrier app providing an icon to use to represent the
      * carrier. If not provided, the app's launcher icon will be used as a fallback.
      */
diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java
index fb529b9..881f628 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -36,12 +36,12 @@
         final Color color = Color.valueOf(Color.WHITE);
         // Default should not support dark text!
         WallpaperColors colors = new WallpaperColors(color, null, null, 0);
-        Assert.assertTrue("Default behavior is not to support dark text",
+        Assert.assertTrue("Default behavior is not to support dark text.",
                 (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0);
 
         // Override it
         colors = new WallpaperColors(color, null, null, WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
-        Assert.assertFalse("Forcing dark text support doesn't work",
+        Assert.assertFalse("Forcing dark text support doesn't work.",
                 (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0);
     }
 
@@ -57,15 +57,18 @@
         int hints = WallpaperColors.fromBitmap(image).getColorHints();
         boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
         boolean supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
-        Assert.assertTrue("White surface should support dark text", supportsDarkText);
-        Assert.assertFalse("White surface shouldn't support dark theme", supportsDarkTheme);
+        boolean fromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0;
+        Assert.assertTrue("White surface should support dark text.", supportsDarkText);
+        Assert.assertFalse("White surface shouldn't support dark theme.", supportsDarkTheme);
+        Assert.assertTrue("From bitmap should be true if object was created "
+                + "using WallpaperColors#fromBitmap.", fromBitmap);
 
         canvas.drawColor(Color.BLACK);
         hints = WallpaperColors.fromBitmap(image).getColorHints();
         supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
         supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
-        Assert.assertFalse("Black surface shouldn't support dark text", supportsDarkText);
-        Assert.assertTrue("Black surface should support dark theme", supportsDarkTheme);
+        Assert.assertFalse("Black surface shouldn't support dark text.", supportsDarkText);
+        Assert.assertTrue("Black surface should support dark theme.", supportsDarkTheme);
 
         Paint paint = new Paint();
         paint.setStyle(Paint.Style.FILL);
@@ -75,7 +78,12 @@
         supportsDarkText = (WallpaperColors.fromBitmap(image)
                 .getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
         Assert.assertFalse("Light surface shouldn't support dark text "
-                + "when it contains dark pixels", supportsDarkText);
+                + "when it contains dark pixels.", supportsDarkText);
+
+        WallpaperColors colors = new WallpaperColors(Color.valueOf(Color.GREEN), null, null);
+        fromBitmap = (colors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) != 0;
+        Assert.assertFalse("Object created from public constructor should not contain "
+                + "HINT_FROM_BITMAP.", fromBitmap);
     }
 
     /**
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index 6dc9ba7..d46fff4 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -99,20 +99,39 @@
     }
 
     @Test
-    public void tonal_excludeBlacklistedColor() {
+    public void tonal_blacklistTest() {
         // Make sure that palette generation will fail.
-        Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+        final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
 
         // Creating a WallpaperColors object that contains *only* blacklisted colors.
-        float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
-        WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)),
-                null, null, 0);
+        final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
+        final int blacklistedColor = ColorUtils.HSLToColor(hsl);
+        WallpaperColors colorsFromBitmap = new WallpaperColors(Color.valueOf(blacklistedColor),
+                null, null, WallpaperColors.HINT_FROM_BITMAP);
 
         // Make sure that palette generation will fail
-        GradientColors normal = new GradientColors();
-        tonal.extractInto(colors, normal, new GradientColors(),
+        final GradientColors normal = new GradientColors();
+        tonal.extractInto(colorsFromBitmap, normal, new GradientColors(),
                 new GradientColors());
         assertTrue("Cannot generate a tonal palette from blacklisted colors.",
                 normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
     }
+
+    @Test
+    public void tonal_ignoreBlacklistTest() {
+        final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+
+        // Creating a WallpaperColors object that contains *only* blacklisted colors.
+        final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
+        final int blacklistedColor = ColorUtils.HSLToColor(hsl);
+        WallpaperColors colors = new WallpaperColors(Color.valueOf(blacklistedColor),
+                null, null);
+
+        // Blacklist should be ignored when HINT_FROM_BITMAP isn't present.
+        final GradientColors normal = new GradientColors();
+        tonal.extractInto(colors, normal, new GradientColors(),
+                new GradientColors());
+        assertTrue("Blacklist should never be used on WallpaperColors generated using "
+                + "default constructor.", normal.getMainColor() == blacklistedColor);
+    }
 }
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java
similarity index 93%
rename from core/tests/coretests/src/android/net/IpPrefixTest.java
rename to tests/net/java/android/net/IpPrefixTest.java
index 4f2387d..b5b2c07 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/tests/net/java/android/net/IpPrefixTest.java
@@ -16,18 +16,27 @@
 
 package android.net;
 
-import android.net.IpPrefix;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.net.InetAddress;
-import java.util.Random;
-import junit.framework.TestCase;
-
-import static android.test.MoreAsserts.assertNotEqual;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-public class IpPrefixTest extends TestCase {
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.net.InetAddress;
+import java.util.Random;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpPrefixTest {
 
     private static InetAddress Address(String addr) {
         return InetAddress.parseNumericAddress(addr);
@@ -42,7 +51,7 @@
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
     };
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         IpPrefix p;
         try {
@@ -103,6 +112,7 @@
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testTruncation() {
         IpPrefix p;
 
@@ -170,7 +180,7 @@
         assertFalse(o2.equals(o1));
     }
 
-    @SmallTest
+    @Test
     public void testEquals() {
         IpPrefix p1, p2;
 
@@ -212,7 +222,7 @@
         assertAreNotEqual(p1, p2);
     }
 
-    @SmallTest
+    @Test
     public void testContains() {
         IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
         assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
@@ -240,7 +250,7 @@
         assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
     }
 
-    @SmallTest
+    @Test
     public void testHashCode() {
         IpPrefix p = new IpPrefix(new byte[4], 0);
         Random random = new Random();
@@ -261,12 +271,12 @@
               assertEquals(p.hashCode(), oldP.hashCode());
             }
             if (p.hashCode() != oldP.hashCode()) {
-              assertNotEqual(p, oldP);
+              assertNotEquals(p, oldP);
             }
         }
     }
 
-    @SmallTest
+    @Test
     public void testHashCodeIsNotConstant() {
         IpPrefix[] prefixes = {
             new IpPrefix("2001:db8:f00::ace:d00d/127"),
@@ -276,12 +286,12 @@
         };
         for (int i = 0; i < prefixes.length; i++) {
           for (int j = i + 1; j < prefixes.length; j++) {
-            assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+            assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
           }
         }
     }
 
-    @SmallTest
+    @Test
     public void testMappedAddressesAreBroken() {
         // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
         // we are unable to comprehend that.
@@ -318,13 +328,16 @@
       assertEquals(p, p2);
     }
 
+    @Test
     public void testParceling() {
         IpPrefix p;
 
         p = new IpPrefix("2001:4860:db8::/64");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv6());
 
         p = new IpPrefix("192.0.2.0/25");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv4());
     }
 }
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/tests/net/java/android/net/LinkAddressTest.java
similarity index 91%
rename from core/tests/coretests/src/android/net/LinkAddressTest.java
rename to tests/net/java/android/net/LinkAddressTest.java
index adf8d95..c1ad946 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/tests/net/java/android/net/LinkAddressTest.java
@@ -16,6 +16,23 @@
 
 package android.net;
 
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
+import static android.system.OsConstants.IFA_F_TEMPORARY;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -27,44 +44,35 @@
 import java.util.Comparator;
 import java.util.List;
 
-import android.net.LinkAddress;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
-import static android.test.MoreAsserts.assertNotEqual;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TEMPORARY;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-/**
- * Tests for {@link LinkAddress}.
- */
-public class LinkAddressTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkAddressTest {
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
     private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
     private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
 
+    @Test
     public void testConstants() {
         // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
-        assertNotEqual(0, RT_SCOPE_HOST);
-        assertNotEqual(0, RT_SCOPE_LINK);
-        assertNotEqual(0, RT_SCOPE_SITE);
+        assertNotEquals(0, RT_SCOPE_HOST);
+        assertNotEquals(0, RT_SCOPE_LINK);
+        assertNotEquals(0, RT_SCOPE_SITE);
 
-        assertNotEqual(0, IFA_F_DEPRECATED);
-        assertNotEqual(0, IFA_F_PERMANENT);
-        assertNotEqual(0, IFA_F_TENTATIVE);
+        assertNotEquals(0, IFA_F_DEPRECATED);
+        assertNotEquals(0, IFA_F_PERMANENT);
+        assertNotEquals(0, IFA_F_TENTATIVE);
     }
 
+    @Test
     public void testConstructors() throws SocketException {
         LinkAddress address;
 
@@ -74,12 +82,14 @@
         assertEquals(25, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv4());
 
         address = new LinkAddress(V6_ADDRESS, 127);
         assertEquals(V6_ADDRESS, address.getAddress());
         assertEquals(127, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv6());
 
         // Nonsensical flags/scopes or combinations thereof are acceptable.
         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
@@ -87,12 +97,14 @@
         assertEquals(64, address.getPrefixLength());
         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
         assertEquals(RT_SCOPE_LINK, address.getScope());
+        assertTrue(address.isIPv6());
 
         address = new LinkAddress(V4 + "/23", 123, 456);
         assertEquals(V4_ADDRESS, address.getAddress());
         assertEquals(23, address.getPrefixLength());
         assertEquals(123, address.getFlags());
         assertEquals(456, address.getScope());
+        assertTrue(address.isIPv4());
 
         // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
         List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
@@ -174,6 +186,7 @@
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testAddressScopes() {
         assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
         assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
@@ -216,6 +229,7 @@
         assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
     }
 
+    @Test
     public void testEqualsAndSameAddressAs() {
         LinkAddress l1, l2, l3;
 
@@ -293,26 +307,17 @@
         assertIsSameAddressAs(l1, l2);
     }
 
+    @Test
     public void testHashCode() {
-        LinkAddress l;
+        LinkAddress l1, l2;
 
-        l = new LinkAddress(V4_ADDRESS, 23);
-        assertEquals(-982787, l.hashCode());
+        l1 = new LinkAddress(V4_ADDRESS, 23);
+        l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
 
-        l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
-        assertEquals(-971865, l.hashCode());
-
-        l = new LinkAddress(V4_ADDRESS, 27);
-        assertEquals(-982743, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 64);
-        assertEquals(1076522926, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 128);
-        assertEquals(1076523630, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
-        assertEquals(1076524846, l.hashCode());
+        l1 = new LinkAddress(V6_ADDRESS, 128);
+        l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
     }
 
     private LinkAddress passThroughParcel(LinkAddress l) {
@@ -334,6 +339,7 @@
       assertEquals(l, l2);
     }
 
+    @Test
     public void testParceling() {
         LinkAddress l;
 
@@ -352,6 +358,7 @@
         assertFalse(msg, l.isGlobalPreferred());
     }
 
+    @Test
     public void testIsGlobalPreferred() {
         LinkAddress l;
 
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f0b3724..296cb76 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -346,7 +346,7 @@
         // Apps that opt out explicitly are not supported
         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
         Bundle metaData = new Bundle();
-        metaData.putBoolean(VpnService.METADATA_SUPPORTS_ALWAYS_ON, false);
+        metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
         svcInfo.metaData = metaData;
         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
     }
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index c4965a0..53a9b5a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -17,7 +17,10 @@
 package com.android.server.connectivity.tethering;
 
 import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.STATS_PER_IFACE;
+import static android.net.NetworkStats.STATS_PER_UID;
 import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
 import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
 import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
@@ -85,6 +88,8 @@
             ArgumentCaptor.forClass(ArrayList.class);
     private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
             ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
+    private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
+            ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
     private MockContentResolver mContentResolver;
 
     @Before public void setUp() {
@@ -103,7 +108,7 @@
 
     private void setupFunctioningHardwareInterface() {
         when(mHardware.initOffloadConfig()).thenReturn(true);
-        when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
+        when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
                 .thenReturn(true);
         when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
     }
@@ -371,7 +376,6 @@
         assertEquals(stats.txBytes, entry.txBytes);
         assertEquals(SET_DEFAULT, entry.set);
         assertEquals(TAG_NONE, entry.tag);
-        assertEquals(UID_TETHERING, entry.uid);
     }
 
     @Test
@@ -410,20 +414,33 @@
         ethernetStats.txBytes = 100000;
         offload.setUpstreamLinkProperties(null);
 
-        NetworkStats stats = mTetherStatsProviderCaptor.getValue().getTetherStats();
+        ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
+        NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE);
+        NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID);
+
         assertEquals(2, stats.size());
+        assertEquals(2, perUidStats.size());
 
         NetworkStats.Entry entry = null;
+        for (int i = 0; i < stats.size(); i++) {
+            assertEquals(UID_ALL, stats.getValues(i, entry).uid);
+            assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid);
+        }
+
         int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
         int mobilePosition = 1 - ethernetPosition;
 
         entry = stats.getValues(mobilePosition, entry);
         assertNetworkStats(mobileIface, mobileStats, entry);
+        entry = perUidStats.getValues(mobilePosition, entry);
+        assertNetworkStats(mobileIface, mobileStats, entry);
 
         ethernetStats.rxBytes = 12345 + 100000;
         ethernetStats.txBytes = 54321 + 100000;
         entry = stats.getValues(ethernetPosition, entry);
         assertNetworkStats(ethernetIface, ethernetStats, entry);
+        entry = perUidStats.getValues(ethernetPosition, entry);
+        assertNetworkStats(ethernetIface, ethernetStats, entry);
     }
 
     @Test
@@ -489,4 +506,17 @@
         waitForIdle();
         inOrder.verify(mHardware).stopOffloadControl();
     }
+
+    @Test
+    public void testDataLimitCallback() throws Exception {
+        setupFunctioningHardwareInterface();
+        enableOffload();
+
+        final OffloadController offload = makeOffloadController();
+        offload.start();
+
+        OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+        callback.onStoppedLimitReached();
+        verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
+    }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index feb46d3..fa99795 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -31,6 +31,8 @@
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
+import static android.net.NetworkStats.STATS_PER_IFACE;
+import static android.net.NetworkStats.STATS_PER_UID;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
@@ -823,17 +825,24 @@
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectCurrentTime();
         expectDefaultSettings();
-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
-                .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
 
+        // Traffic seen by kernel counters (includes software tethering).
+        final NetworkStats ifaceStats = new NetworkStats(getElapsedRealtime(), 1)
+                .addIfaceValues(TEST_IFACE, 1536L, 12L, 384L, 3L);
+        // Hardware tethering traffic, not seen by kernel counters.
+        final NetworkStats tetherStatsHardware = new NetworkStats(getElapsedRealtime(), 1)
+                .addIfaceValues(TEST_IFACE, 512L, 4L, 128L, 1L);
+
+        // Traffic for UID_RED.
         final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
-        final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
+        // All tethering traffic, both hardware and software.
         final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
                 .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
                         0L);
 
-        expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
+        expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
+        expectNetworkStatsUidDetail(uidStats, tetherStats);
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -1013,10 +1022,16 @@
     }
 
     private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
+        expectNetworkStatsSummary(summary, new NetworkStats(0L, 0));
+    }
+
+    private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats)
+            throws Exception {
         when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]);
 
-        expectNetworkStatsSummaryDev(summary);
-        expectNetworkStatsSummaryXt(summary);
+        expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats);
+        expectNetworkStatsSummaryDev(summary.clone());
+        expectNetworkStatsSummaryXt(summary.clone());
     }
 
     private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
@@ -1027,17 +1042,21 @@
         when(mNetManager.getNetworkStatsSummaryXt()).thenReturn(summary);
     }
 
-    private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
-        expectNetworkStatsUidDetail(detail, new String[0], new NetworkStats(0L, 0));
+    private void expectNetworkStatsTethering(int how, NetworkStats stats)
+            throws Exception {
+        when(mNetManager.getNetworkStatsTethering(how)).thenReturn(stats);
     }
 
-    private void expectNetworkStatsUidDetail(
-            NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
+    private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
+        expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
+    }
+
+    private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
             throws Exception {
         when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
 
         // also include tethering details, since they are folded into UID
-        when(mNetManager.getNetworkStatsTethering()).thenReturn(tetherStats);
+        when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
     }
 
     private void expectDefaultSettings() throws Exception {
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index ac5df05..dc5ba0c 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -1,5 +1,6 @@
 package android.net.wifi;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
@@ -313,6 +314,7 @@
              };
     }
 
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public RttCapabilities getRttCapabilities() {
         synchronized (mCapabilitiesLock) {
             if (mRttCapabilities == null) {
@@ -925,6 +927,51 @@
         public void onAborted();
     }
 
+    /**
+     * A parcelable that contains rtt client information.
+     *
+     * @hide
+     */
+    public static class RttClient implements Parcelable {
+        // Package name of RttClient.
+        private final String mPackageName;
+
+        public RttClient(String packageName) {
+            mPackageName = packageName;
+        }
+
+        protected RttClient(Parcel in) {
+            mPackageName = in.readString();
+        }
+
+        public static final Creator<RttManager.RttClient> CREATOR =
+                new Creator<RttManager.RttClient>() {
+            @Override
+            public RttManager.RttClient createFromParcel(Parcel in) {
+                return new RttManager.RttClient(in);
+            }
+
+            @Override
+            public RttManager.RttClient[] newArray(int size) {
+                return new RttManager.RttClient[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int i) {
+            parcel.writeString(mPackageName);
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+    }
+
     private boolean rttParamSanity(RttParams params, int index) {
         if (mRttCapabilities == null) {
             if(getRttCapabilities() == null) {
@@ -1236,7 +1283,8 @@
         mAsyncChannel.connectSync(mContext, handler, messenger);
         // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
         // synchronously, which causes RttService to receive the wrong replyTo value.
-        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION,
+                new RttClient(context.getPackageName()));
         mAsyncChannel.sendMessage(CMD_OP_REG_BINDER, key[0]);
     }