Merge "Don't call surface.remove if surface is null." into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 4f117ee..7584ba8 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);
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..1258554 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);
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..b2fd169 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1006,11 +1006,6 @@
             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);
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/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/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index c0b82b4..61b0eb0 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -36,161 +36,72 @@
 import java.util.List;
 
 /**
- * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users
- * with quick access to activities other than an app's main activity in the currently-active
- * launcher.  For example,
- * an email app may publish the "compose new email" action, which will directly open the
- * compose activity.  The {@link ShortcutInfo} class contains information about each of the
- * shortcuts themselves.
+ * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users with quick
+ * access to activities other than an app's main activity in the currently-active launcher, provided
+ * that the launcher supports app shortcuts.  For example, an email app may publish the "compose new
+ * email" action, which will directly open the compose activity.  The {@link ShortcutInfo} class
+ * contains information about each of the shortcuts themselves.
  *
- * <h3>Static Shortcuts and Dynamic Shortcuts</h3>
+ * <p>This page discusses the implementation details of the <code>ShortcutManager</code> class. For
+ * guidance on performing operations on app shortcuts within your app, see the
+ * <a href="/guide/topics/ui/shortcuts.html">App Shortcuts</a> feature guide.
  *
- * <p>
- * There are several different types of shortcuts:
+ * <h3>Shortcut characteristics</h3>
  *
- * <ul>
- * <li><p>Static shortcuts are declared in a resource XML file, which is referenced in the publisher
- * app's <code>AndroidManifest.xml</code> file. These shortcuts are visually associated with an
- * app's launcher icon.
- * <p>Static shortcuts are published when an app is installed, and the details of these shortcuts
- * change when an app is upgraded with an updated XML file. Static shortcuts are immutable, and
- * their definitions, such as icons and labels, cannot be changed dynamically without upgrading the
- * publisher app.</li>
+ * This section describes in-depth details about each shortcut type's usage and availability.
  *
- * <li>Dynamic shortcuts are published at runtime using this class's APIs. These shortcuts are
- * visually associated with an app's launcher icon. Apps can publish, update, and remove dynamic
- * shortcuts at runtime.
- * </ul>
+ * <p class="note"><b>Important security note:</b> All shortcut information is stored in
+ * <a href="/training/articles/direct-boot.html">credential encrypted storage</a>, so your app
+ * cannot access a user's shortcuts until after they've unlocked the device.
  *
- * <p>Only main activities&mdash;activities that handle the {@code MAIN} action and the
- * {@code LAUNCHER} category&mdash;can have shortcuts.
- * If an app has multiple main activities, these activities have different sets
- * of shortcuts.
+ * <h4>Static and dynamic shortcuts</h4>
  *
  * <p>Static shortcuts and dynamic shortcuts are shown in a supported launcher when the user
- * long-presses on an app's launcher icon. Note that the actual gesture may be different
- * depending on the launcher app.
+ * performs a specific gesture. On currently-supported launchers, the gesture is a long-press on the
+ * app's launcher icon, but the actual gesture may be different on other launcher apps.
  *
- * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
- * static and dynamic shortcuts combined.
+ * <p>The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
  *
+ * <h4>Pinned shortcuts</h4>
  *
- * <h3>Pinning Shortcuts</h3>
+ * <p>Because pinned shortcuts appear in the launcher itself, they're always visible. A pinned
+ * shortcut is removed from the launcher only in the following situations:
+ * <ul>
+ *     <li>The user removes it.
+ *     <li>The publisher app associated with the shortcut is uninstalled.
+ *     <li>The user performs the clear data action on the publisher app from the device's
+ *     <b>Settings</b> app.
+ * </ul>
  *
- * <p>Apps running in the foreground can also <em>pin</em> shortcuts at runtime, subject to user
- * permission, using this class's APIs. Each pinned shortcut is a copy of a static shortcut or a
- * dynamic shortcut. Although users can pin a shortcut multiple times, the system calls the pinning
- * API only once to complete the pinning process. Unlike static and dynamic shortcuts, pinned
- * shortcuts appear as separate icons, visually distinct from the app's launcher icon, in the
- * launcher. There is no limit to the number of pinned shortcuts that an app can create.
+ * <p>Because the system performs
+ * <a href="/guide/topics/ui/shortcuts.html#backup-and-restore">backup and restore</a> on pinned
+ * shortcuts automatically, these shortcuts' IDs should contain either stable, constant strings or
+ * server-side identifiers, rather than identifiers generated locally that might not make sense on
+ * other devices.
  *
- * <p>Pinned shortcuts <strong>cannot</strong> be removed by publisher apps. They're removed only
- * when the user removes them, when the publisher app is uninstalled, or when the user performs the
- * clear data action on the publisher app from the device's <b>Settings</b> app.
+ * <h3>Shortcut display order</h3>
  *
- * <p>However, the publisher app can <em>disable</em> pinned shortcuts so they cannot be started.
- * See the following sections for details.
+ * <p>When the launcher displays an app's shortcuts, they should appear in the following order:
  *
- * <h3>Updating and Disabling Shortcuts</h3>
+ * <ul>
+ *   <li>Static shortcuts (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
+ *   and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
+ *   <li>Within each shortcut type (static and dynamic), sort the shortcuts in order of increasing
+ *   rank according to {@link ShortcutInfo#getRank()}.
+ * </ul>
  *
- * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
- * the pinned shortcut will still be visible and launchable.  This allows an app to have
- * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
+ * <p>Shortcut ranks are non-negative, sequential integers that determine the order in which
+ * shortcuts appear, assuming that the shortcuts are all in the same category. You can update ranks
+ * of existing shortcuts when you call {@link #updateShortcuts(List)},
+ * {@link #addDynamicShortcuts(List)}, or {@link #setDynamicShortcuts(List)}.
  *
- * <p>For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
- * <ol>
- *     <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
- *     conversations (c1, c2, ..., c5).
+ * <p class="note"><b>Note:</b> Ranks are auto-adjusted so that they're unique for each type of
+ * shortcut (static or dynamic). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and
+ * 2, adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut
+ * at the second position. In response, the third and fourth shortcuts move closer to the bottom of
+ * the shortcut list, with their ranks changing to 2 and 3, respectively.
  *
- *     <li>The user pins all 5 of the shortcuts.
- *
- *     <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
- *     so the publisher app
- *     re-publishes its dynamic shortcuts.  The new dynamic shortcut list is:
- *     c4, c5, ..., c8.
- *     The publisher app has to remove c1, c2, and c3 because it can't have more than
- *     5 dynamic shortcuts.
- *
- *     <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
- *     shortcuts for these conversations are still available and launchable.
- *
- *     <li>At this point, the user can access a total of 8 shortcuts that link to activities in
- *     the publisher app, including the 3 pinned
- *     shortcuts, even though an app can have at most 5 dynamic shortcuts.
- *
- *     <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
- *     8 shortcuts, when, for example, the chat peers' icons have changed.
- * </ol>
- * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
- * can also be used
- * to update existing shortcuts with the same IDs, but they <b>cannot</b> be used
- * for updating non-dynamic, pinned shortcuts because these two methods try to convert the given
- * lists of shortcuts to dynamic shortcuts.
- *
- *
- * <h4>Disabling Static Shortcuts</h4>
- * <p>When an app is upgraded and the new version
- * no longer uses a static shortcut that appeared in the previous version, this deprecated
- * shortcut isn't published as a static shortcut.
- *
- * <p>If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher,
- * but it's disabled automatically. When a pinned shortcut is disabled, this class's APIs cannot
- * update it.
- *
- * <h4>Disabling Dynamic Shortcuts</h4>
- * Sometimes pinned shortcuts become obsolete and may not be usable.  For example, a pinned shortcut
- * to a group chat becomes unusable when the associated group chat is deleted.  In cases like this,
- * apps should use {@link #disableShortcuts(List)}, which removes the specified dynamic
- * shortcuts and also makes any specified pinned shortcuts un-launchable.
- * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disable shortcuts
- * and show users a custom error message when they attempt to launch the disabled shortcuts.
- *
- *
- * <h3>Publishing Static Shortcuts</h3>
- *
- * <p>
- * In order to add static shortcuts to your app, first add
- * {@code <meta-data android:name="android.app.shortcuts" />} to your main activity in
- * AndroidManifest.xml:
- * <pre>
- *&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
- *             package="com.example.myapplication"&gt;
- *  &lt;application ... &gt;
- *    &lt;activity android:name="Main"&gt;
- *      &lt;intent-filter&gt;
- *        &lt;action android:name="android.intent.action.MAIN" /&gt;
- *        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
- *      &lt;/intent-filter&gt;
- *      <strong>&lt;meta-data android:name="android.app.shortcuts"
- *                 android:resource="@xml/shortcuts" /&gt;</strong>
- *    &lt;/activity&gt;
- *  &lt;/application&gt;
- *&lt;/manifest&gt;
- * </pre>
- *
- * Then, define your app's static shortcuts in the <code>res/xml/shortcuts.xml</code>
- * file:
- * <pre>
- *&lt;shortcuts xmlns:android="http://schemas.android.com/apk/res/android"&gt;
- *  &lt;shortcut
- *    android:shortcutId="compose"
- *    android:enabled="true"
- *    android:icon="@drawable/compose_icon"
- *    android:shortcutShortLabel="@string/compose_shortcut_short_label1"
- *    android:shortcutLongLabel="@string/compose_shortcut_long_label1"
- *    android:shortcutDisabledMessage="@string/compose_disabled_message1"&gt;
- *    &lt;intent
- *      android:action="android.intent.action.VIEW"
- *      android:targetPackage="com.example.myapplication"
- *      android:targetClass="com.example.myapplication.ComposeActivity" /&gt;
- *    &lt;!-- If your shortcut is associated with multiple intents, include them
- *         here. The last intent in the list is what the user sees when they
- *         launch this shortcut. --&gt;
- *    &lt;categories android:name="android.shortcut.conversation" /&gt;
- *  &lt;/shortcut&gt;
- *  &lt;!-- Specify more shortcuts here. --&gt;
- *&lt;/shortcuts&gt;
- * </pre>
+ * <h3>Options for static shortcuts</h3>
  *
  * The following list includes descriptions for the different attributes within a static shortcut:
  * <dl>
@@ -236,9 +147,10 @@
  *   {@code android:action} is mandatory.
  *   See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the
  *   other supported tags.
- *   You can provide multiple intents for a single shortcut so that the last defined activity is launched
- *   with the other activities in the <a href="/guide/components/tasks-and-back-stack.html">back stack</a>.
- *   See {@link android.app.TaskStackBuilder} for details.
+ *   <p>You can provide multiple intents for a single shortcut so that the last defined activity is
+ *   launched with the other activities in the
+ *   <a href="/guide/components/tasks-and-back-stack.html">back stack</a>. See
+ *   {@link android.app.TaskStackBuilder} for details.
  *   <p><b>Note:</b> String resources may not be used within an {@code <intent>} element.
  *   </dd>
  *   <dt>{@code categories}</dt>
@@ -247,337 +159,92 @@
  *   </dd>
  * </dl>
  *
- * <h3>Publishing Dynamic Shortcuts</h3>
+ * <h3>Updating shortcuts</h3>
  *
- * <p>
- * Apps can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
- * or {@link #addDynamicShortcuts(List)}.  The {@link #updateShortcuts(List)} method can also be
- * used to update existing, mutable shortcuts.
- * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove
- * dynamic shortcuts.
- *
- * <p>The following code snippet shows how to create a single dynamic shortcut:
- * <pre>
- *ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
- *
- *ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
- *    .setShortLabel("Web site")
- *    .setLongLabel("Open the web site")
- *    .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
- *    .setIntent(new Intent(Intent.ACTION_VIEW,
- *                   Uri.parse("https://www.mysite.example.com/")))
- *    .build();
- *
- *shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
- * </pre>
- *
- * <h3>Publishing Pinned Shortcuts</h3>
- *
- * <p>Apps can pin an existing shortcut (either static or dynamic) or an entirely new shortcut to a
- * supported launcher programatically using {@link #requestPinShortcut(ShortcutInfo, IntentSender)}.
- * You pass two arguments into this method:
- *
- * <ul>
- *   <li>A {@link ShortcutInfo} object &ndash; If the shortcut already exists, this object should
- *   contain only the shortcut's ID. Otherwise, the new {@link ShortcutInfo} object must contain an
- *   ID, an intent, and a short label for the new shortcut.
- *   <li><p>A {@link android.app.PendingIntent} object &ndash; This intent represents the callback
- *   that your app receives if the shortcut is successfully pinned to the device's launcher.
- *   <p><b>Note:</b> If the user doesn't allow the shortcut to be pinned to the launcher, the
- *   pinning process fails, and the {@link Intent} object that is passed into this
- *   {@link android.app.PendingIntent} object isn't executed.
- *   <div class="note"><p><b>Note:</b> Due to background execution limits introduced in Android
- *   {@link VERSION_CODES#O}, it's best to use a
- *   <a href="{@docRoot}guide/components/broadcasts.html#manifest-declared_receivers">
- *   manifest-declared receiver</a> to receive a callback.
- *   <p>Also, to prevent other apps from invoking the receiver, add the attribute assignment
- *   <code>android:exported="false"</code> to the receiver's manifest entry.</p></div>
- * </ul>
- *
- * The following code snippet shows how to pin a single shortcut that already exists and is enabled:
- *
- * <pre>
- *ShortcutManager mShortcutManager =
- *        context.getSystemService(ShortcutManager.class);
- *
- *if (mShortcutManager.isRequestPinShortcutSupported()) {
- *
- *    // This example defines a new shortcut; that is, this shortcut hasn't
- *    // been published before.
- *    ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder()
- *            .setIcon(myIcon)
- *            .setShortLabel("My awesome shortcut")
- *            .setIntent(myIntent)
- *            .build();
- *
- *    PendingIntent resultPendingIntent = null;
- *
- *    // Create the following Intent and PendingIntent objects only if your app
- *    // needs to be notified that the user allowed the shortcut to be pinned.
- *    // Use a boolean value, such as "appNeedsNotifying", to define this behavior.
- *    if (appNeedsNotifying) {
- *        // We assume here the app has a manifest-declared receiver "MyReceiver".
- *        Intent pinnedShortcutCallbackIntent = new Intent(context, MyReceiver.class);
- *
- *        // Configure the intent so that your app's broadcast receiver gets
- *        // the callback successfully.
- *        PendingIntent successCallback = PendingIntent.createBroadcast(context, 0,
- *                pinnedShortcutCallbackIntent);
- *
- *        resultPendingIntent = successCallback.getIntentSender();
- *    }
- *
- *    mShortcutManager.requestPinShortcut(pinShortcutInfo, resultPendingIntent);
- *}
- * </pre>
- *
- * <p class="note"><strong>Note:</strong> As you add logic in your app to make requests to pin
- * shortcuts, keep in mind that not all launchers support pinning of shortcuts. To determine whether
- * your app can complete this process on a particular device, check the return value of
- * {@link #isRequestPinShortcutSupported()}. Based on this return value, you might decide to hide
- * the option in your app that allows users to pin a shortcut.
- *
- * <p class="note"><strong>Note:</strong> See also the support library APIs
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
- * Context)} and
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut(
- * Context, ShortcutInfoCompat, IntentSender)}, which works on Android versions lower than
- * {@link VERSION_CODES#O} by falling back to the deprecated private intent
- * {@code com.android.launcher.action.INSTALL_SHORTCUT}.
- *
- * <h4>Custom Activity for Pinning Shortcuts</h4>
- *
- * <p>You can also create a specialized activity that helps users create shortcuts, complete with
- * custom options and a confirmation button. In your app's manifest file, add
- * {@link Intent#ACTION_CREATE_SHORTCUT} to the activity's <code>&lt;intent-filter&gt;</code>
- * element, as shown in the following snippet:
- *
- * <pre>
- *&lt;manifest&gt;
- *    ...
- *    &lt;application&gt;
- *        &lt;activity android:name="com.example.MyCustomPromptToPinShortcut" ... &gt;
- *            &lt;intent-filter
- *                    action android:name="android.intent.action.ACTION_CREATE_SHORTCUT"&gt;
- *            ...
- *            &lt;/intent-filter&gt;
- *        &lt;/activity&gt;
- *        ...
- *    &lt;/application&gt;
- *&lt;/manifest&gt;
- * </pre>
- *
- * <p>When you use this specialized activity in your app, the following sequence of steps takes
- * place:</p>
- *
+ * <p>As an example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
  * <ol>
- *   <li>The user attempts to create a shortcut, triggering the system to start the specialized
- *   activity.</li>
- *   <li>The user sets options for the shortcut.</li>
- *   <li>The user selects the confirmation button, allowing your app to create the shortcut using
- *   the {@link #createShortcutResultIntent(ShortcutInfo)} method. This method returns an
- *   {@link Intent}, which your app relays back to the previously-executing activity using
- *   {@link Activity#setResult(int)}.</li>
- *   <li>Your app calls {@link Activity#finish()} on the activity used for creating the customized
- *   shortcut.</li>
+ *     <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
+ *     conversations (c1, c2, ..., c5).
+ *
+ *     <li>The user pins all 5 of the shortcuts.
+ *
+ *     <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
+ *     so the publisher app
+ *     re-publishes its dynamic shortcuts.  The new dynamic shortcut list is:
+ *     c4, c5, ..., c8.
+ *     The publisher app has to remove c1, c2, and c3 because it can't have more than
+ *     5 dynamic shortcuts.
+ *
+ *     <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
+ *     shortcuts for these conversations are still available and launchable.
+ *
+ *     <li>At this point, the user can access a total of 8 shortcuts that link to activities in
+ *     the publisher app, including the 3 pinned shortcuts, even though an app can have at most 5
+ *     dynamic shortcuts.
+ *
+ *     <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
+ *     8 shortcuts, when, for example, the chat peers' icons have changed.
+ *     <p>The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
+ *     can also be used to update existing shortcuts with the same IDs, but they <b>cannot</b> be
+ *     used for updating non-dynamic, pinned shortcuts because these 2 methods try to convert the
+ *     given lists of shortcuts to dynamic shortcuts.
  * </ol>
  *
- * <h3>Shortcut Intents</h3>
+ * <h3>Shortcut intents</h3>
+ *
  * <p>
  * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
  * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
  * flags; otherwise, if the app is already running, the app is simply brought to
  * the foreground, and the target activity may not appear.
  *
- * <p>The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of
- * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder}
- * in order to launch an activity with other activities in the back stack.
- * When the user selects a shortcut to load an activity with a back stack,
- * then presses the back key, a parent activity from the same app will be shown
- * instead of the user being navigated back to the launcher.
- *
- * <p>Static shortcuts can also have multiple intents to achieve the same effect.
- * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple
- * <code>&lt;intent&gt;</code> elements within a single <code>&lt;shortcut&gt;</code> element.
- * The last intent specifies what the user sees when they launch a shortcut.
- *
  * <p>Static shortcuts <b>cannot</b> have custom intent flags.
  * The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
- * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set.
- * This means, when the app is already running, all the existing activities will be
- * destroyed when a static shortcut is launched.
- * If this behavior is not desirable, you can use a <em>trampoline activity</em>,
- * or an invisible activity that starts another activity in {@link Activity#onCreate},
- * then calls {@link Activity#finish()}.
- * The first activity should include an attribute setting
- * of {@code android:taskAffinity=""} in the app's <code>AndroidManifest.xml</code>
- * file, and the intent within the static shortcut should point at this first activity.
+ * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set. This means, when the app is already running, all
+ * the existing activities in your app will be destroyed when a static shortcut is launched.
+ * If this behavior is not desirable, you can use a <em>trampoline activity</em>, or an invisible
+ * activity that starts another activity in {@link Activity#onCreate}, then calls
+ * {@link Activity#finish()}:
+ * <ol>
+ *     <li>In the <code>AndroidManifest.xml</code> file, the trampoline activity should include the
+ *     attribute assignment {@code android:taskAffinity=""}.
+ *     <li>In the shortcuts resource file, the intent within the static shortcut should point at
+ *     the trampoline activity.
+ * </ol>
  *
+ * <h3>Handling system locale changes</h3>
  *
- * <h3>Showing New Information in a Shortcut</h3>
- * <p>
- * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update
- * a shortcut so that it contains conceptually different information.
+ * <p>Apps should update dynamic and pinned shortcuts when the system locale changes using the
+ * {@link Intent#ACTION_LOCALE_CHANGED} broadcast. When the system locale changes,
+ * <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is reset, so even
+ * background apps can add and update dynamic shortcuts until the rate limit is reached again.
  *
- * <p>For example, a phone app may publish the most frequently called contact as a dynamic
- * shortcut.  Over time, this contact may change. When it does, the app should
- * represent the changed contact with a new shortcut that contains a different ID, using either
- * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating
- * the existing shortcut with {@link #updateShortcuts(List)}.
- * This is because when the shortcut is pinned, changing
- * it to reference a different contact will likely confuse the user.
+ * <h3>Shortcut limits</h3>
  *
- * <p>On the other hand, when the
- * contact's information has changed, such as the name or picture, the app should
- * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too.
+ * <p>Only main activities&mdash;activities that handle the {@code MAIN} action and the
+ * {@code LAUNCHER} category&mdash;can have shortcuts. If an app has multiple main activities, you
+ * need to define the set of shortcuts for <em>each</em> activity.
  *
+ * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
+ * static and dynamic shortcuts combined. There is no limit to the number of pinned shortcuts that
+ * an app can create.
  *
- * <h3>Shortcut Display Order</h3>
- * When the launcher displays the shortcuts that are associated with a particular launcher icon,
- * the shortcuts should appear in the following order:
- * <ul>
- *   <li>First show static shortcuts
- *   (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
- *   and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
- *   <li>Within each category of shortcuts (static and dynamic), sort the shortcuts in order
- *   of increasing rank according to {@link ShortcutInfo#getRank()}.
- * </ul>
- * <p>Shortcut ranks are non-negative, sequential integers
- * that determine the order in which shortcuts appear, assuming that the shortcuts are all in
- * the same category.
- * Ranks of existing shortcuts can be updated with
- * {@link #updateShortcuts(List)}. You can also use {@link #addDynamicShortcuts(List)} and
- * {@link #setDynamicShortcuts(List)}.
+ * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
+ * the pinned shortcut is still visible and launchable.  This allows an app to have more than
+ * {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
  *
- * <p>Ranks are auto-adjusted so that they're unique for each target activity in each category
- * (static or dynamic).  For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
- * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at
- * the second position.
- * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list,
- * with their ranks changing to 2 and 3, respectively.
+ * <h4>Rate limiting</h4>
  *
- * <h3>Rate Limiting</h3>
+ * <p>When <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is active,
+ * {@link #isRateLimitingActive()} returns {@code true}.
  *
- * <p>
- * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and
- * {@link #updateShortcuts(List)} may be rate-limited when called by <em>background apps</em>, or
- * apps with no foreground activity or service.  When you attempt to call these methods
- * from a background app after exceeding the rate limit, these APIs return {@code false}.
- *
- * <p>Apps with a foreground activity or service are not rate-limited.
- *
- * <p>Rate-limiting is reset upon certain events, so that even background apps
- * can call these APIs until the rate limit is reached again.
- * These events include the following:
+ * <p>Rate limiting is reset upon certain events, so even background apps can call these APIs until
+ * the rate limit is reached again. These events include the following:
  * <ul>
  *   <li>An app comes to the foreground.
  *   <li>The system locale changes.
  *   <li>The user performs the <strong>inline reply</strong> action on a notification.
  * </ul>
- *
- * <p>When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}.
- *
- * <h4>Resetting rate-limiting for testing</h4>
- *
- * <p>
- * If your app is rate-limited during development or testing, you can use the
- * <strong>Reset ShortcutManager rate-limiting</strong> development option or
- * the following {@code adb} command to reset it:
- * <pre class="no-pretty-print">
- *$ adb shell cmd shortcut reset-throttling [ --user USER-ID ]
- * </pre>
- *
- * <h3>Handling System Locale Changes</h3>
- *
- * <p>
- * Apps should update dynamic and pinned shortcuts when the system locale changes
- * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast.
- *
- * <p>When the system locale changes, rate-limiting is reset, so even background apps
- * can add and update dynamic shortcuts until the rate limit is reached again.
- *
- *
- * <h3>Backup and Restore</h3>
- *
- * <p>
- * When an app has the {@code android:allowBackup="true"} attribute assignment included
- * in its <code>AndroidManifest.xml</code> file, pinned shortcuts are
- * backed up automatically and are restored when the user sets up a new device.
- *
- * <h4>Categories of shortcuts that are backed up</h4>
- *
- * <ul>
- *  <li>Pinned shortcuts are backed up.  Bitmap icons are not backed up by the system,
- *  so launcher apps should back them up and restore them so that the user still sees icons
- *  for pinned shortcuts on the launcher.  Apps can always use
- *  {@link #updateShortcuts(List)} to re-publish icons.
- *
- *  <li>Static shortcuts aren't backed up, but when an app is re-installed on a new
- *  device, they are re-published from the <code>AndroidManifest.xml</code> file.
- *
- *  <li>Dynamic shortcuts <b>aren't</b> backed up.
- * </ul>
- *
- * <p>Because dynamic shortcuts are not restored, it is recommended that apps check
- * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()}
- * each time they are launched, and they should re-publish
- * dynamic shortcuts when necessary.
- *
- * <pre>
- *public class MainActivity extends Activity {
- *    public void onCreate(Bundle savedInstanceState) {
- *        super.onCreate(savedInstanceState);
- *        ShortcutManager shortcutManager =
- *                getSystemService(ShortcutManager.class);
- *
- *        if (shortcutManager.getDynamicShortcuts().size() == 0) {
- *            // Application restored. Need to re-publish dynamic shortcuts.
- *            if (shortcutManager.getPinnedShortcuts().size() > 0) {
- *                // Pinned shortcuts have been restored. Use
- *                // updateShortcuts() to make sure they contain
- *                // up-to-date information.
- *            }
- *        }
- *    }
- *    // ...
- *}
- * </pre>
- *
- *
- * <h4>Backup/restore and shortcut IDs</h4>
- * <p>
- * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs
- * should contain either stable, constant strings or server-side identifiers,
- * rather than identifiers generated locally that might not make sense on other devices.
- *
- *
- * <h3>Report Shortcut Usage and Prediction</h3>
- * <p>
- * Launcher apps may be capable of predicting which shortcuts will most likely be
- * used at a given time by examining the shortcut usage history data.
- *
- * <p>In order to provide launchers with such data, publisher apps should
- * report the shortcuts that are used with {@link #reportShortcutUsed(String)}
- * when a shortcut is selected,
- * <b>or when an action equivalent to a shortcut is taken by the user even if it wasn't started
- * with the shortcut</b>.
- *
- * <p>For example, suppose a navigation app supports "navigate to work" as a shortcut.
- * It should then report when the user selects this shortcut <b>and</b> when the user chooses
- * to navigate to work within the app itself.
- * This helps the launcher app
- * learn that the user wants to navigate to work at a certain time every
- * weekday, and it can then show this shortcut in a suggestion list at the right time.
- *
- * <h3>Launcher API</h3>
- *
- * The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
- *
- *
- * <h3>Direct Boot and Shortcuts</h3>
- *
- * All shortcut information is stored in credential encrypted storage, so no shortcuts can be
- * accessed when the user is locked.
  */
 @SystemService(Context.SHORTCUT_SERVICE)
 public class ShortcutManager {
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/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..e6e1da4 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
      **/
 
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/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/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/config.xml b/core/res/res/values/config.xml
index 95aa264..98147e7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -626,10 +626,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/symbols.xml b/core/res/res/values/symbols.xml
index 061413c..af08e24 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2900,7 +2900,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 +2931,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/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/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/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/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/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
index b22a2c1..f178aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.car;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -100,7 +101,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 +111,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 +129,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 +148,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 +172,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 +181,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 +196,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/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/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/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/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 3a4c9f8..901e1e7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -547,6 +547,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;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1d860d6..325ffb4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1346,7 +1346,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 +1366,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;
@@ -12390,7 +12383,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 +12415,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 +12443,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 +12483,7 @@
 
         synchronized(this) {
             mShuttingDown = true;
+            mStackSupervisor.prepareForShutdownLocked();
             updateEventDispatchingLocked();
             timedout = mStackSupervisor.shutdownLocked(timeout);
         }
@@ -14916,6 +14898,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 +15802,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 +23762,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 +24201,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/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8cab918..6b1f758 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1341,7 +1341,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 +1733,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();
         }
     }
 
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..617ba96 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;
 
@@ -1580,8 +1581,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..ad661d7 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -60,6 +60,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 +91,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 +153,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
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f41aa5f..a9c0cb0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3354,12 +3354,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 +3362,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) {
+                    getJobScheduler().cancel(syncOperation.jobId);
+                }
+
                 if (!syncResult.hasError()) {
                     historyMessage = SyncStorageEngine.MESG_SUCCESS;
                     // TODO: set these correctly when the SyncResult is extended to include it
@@ -3404,6 +3408,11 @@
                 if (isLoggable) {
                     Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
                 }
+
+                if (!syncOperation.isPeriodic) {
+                    getJobScheduler().cancel(syncOperation.jobId);
+                }
+
                 if (activeSyncContext.mSyncAdapter != null) {
                     try {
                         mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
@@ -3418,10 +3427,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 +3466,8 @@
                         + activeSyncContext.toString());
             }
             mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
+
+            mLogger.log("closeActiveSyncContext: ", activeSyncContext);
         }
 
         /**
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/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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 28acd9a..845efa6 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());
             }
         }
     };
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/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 dce06f4..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;
             }
 
@@ -702,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/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..4e4d42d 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() {
@@ -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/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/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..81353df 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";
@@ -1646,6 +1652,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,
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/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..983e04d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -85,6 +85,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 +105,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());
     }
@@ -489,4 +491,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());
+    }
 }