Merge "Fix FLAG_ACTIVITY_CLEAR_TOP not working for aliased activities"
diff --git a/api/current.txt b/api/current.txt
index 2fd32c5..c7f0a75 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5705,6 +5705,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSettingAllowed();
     method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -6328,6 +6329,7 @@
     method public long getRxPackets();
     method public long getStartTimeStamp();
     method public int getState();
+    method public int getTag();
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
@@ -6337,6 +6339,8 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
+    field public static final int TAG_ALL = 0; // 0x0
+    field public static final int TAG_ANY = -1; // 0xffffffff
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6345,9 +6349,12 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -28529,6 +28536,7 @@
     field public static java.lang.String DIRECTORY_DCIM;
     field public static java.lang.String DIRECTORY_DOCUMENTS;
     field public static java.lang.String DIRECTORY_DOWNLOADS;
+    field public static java.lang.String DIRECTORY_HOME;
     field public static java.lang.String DIRECTORY_MOVIES;
     field public static java.lang.String DIRECTORY_MUSIC;
     field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -29264,6 +29272,7 @@
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+    field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -34348,6 +34357,7 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
+    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
     method public android.service.notification.Condition copy();
     method public int describeContents();
@@ -34379,7 +34389,6 @@
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
-    method public abstract void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
@@ -43245,7 +43254,7 @@
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
     method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
-    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -43332,7 +43341,7 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.RestrictedCaptionAreaListener {
+  public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
     method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
   }
 
diff --git a/api/removed.txt b/api/removed.txt
index 2c6729d..0bf6594 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -199,6 +199,14 @@
 
 }
 
+package android.service.notification {
+
+  public abstract class ConditionProviderService extends android.app.Service {
+    method public void onRequestConditions(int);
+  }
+
+}
+
 package android.test.mock {
 
   public deprecated class MockPackageManager extends android.content.pm.PackageManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index 5b640cd..3c5e59e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5838,6 +5838,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSettingAllowed();
     method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -6585,6 +6586,7 @@
     method public long getRxPackets();
     method public long getStartTimeStamp();
     method public int getState();
+    method public int getTag();
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
@@ -6594,6 +6596,8 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
+    field public static final int TAG_ALL = 0; // 0x0
+    field public static final int TAG_ANY = -1; // 0xffffffff
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6602,9 +6606,12 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -30556,6 +30563,7 @@
     field public static java.lang.String DIRECTORY_DCIM;
     field public static java.lang.String DIRECTORY_DOCUMENTS;
     field public static java.lang.String DIRECTORY_DOWNLOADS;
+    field public static java.lang.String DIRECTORY_HOME;
     field public static java.lang.String DIRECTORY_MOVIES;
     field public static java.lang.String DIRECTORY_MUSIC;
     field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -31310,6 +31318,7 @@
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+    field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -36528,6 +36537,7 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
+    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
     method public android.service.notification.Condition copy();
     method public int describeContents();
@@ -36559,7 +36569,7 @@
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
-    method public abstract void onRequestConditions(int);
+    method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
@@ -45663,7 +45673,7 @@
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
     method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
-    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -45750,7 +45760,7 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.RestrictedCaptionAreaListener {
+  public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
     method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 47eec48..3e755ae 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5707,6 +5707,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSettingAllowed();
     method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -6330,6 +6331,7 @@
     method public long getRxPackets();
     method public long getStartTimeStamp();
     method public int getState();
+    method public int getTag();
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
@@ -6339,6 +6341,8 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
+    field public static final int TAG_ALL = 0; // 0x0
+    field public static final int TAG_ANY = -1; // 0xffffffff
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6347,9 +6351,12 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -28538,6 +28545,7 @@
     field public static java.lang.String DIRECTORY_DCIM;
     field public static java.lang.String DIRECTORY_DOCUMENTS;
     field public static java.lang.String DIRECTORY_DOWNLOADS;
+    field public static java.lang.String DIRECTORY_HOME;
     field public static java.lang.String DIRECTORY_MOVIES;
     field public static java.lang.String DIRECTORY_MUSIC;
     field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -29274,6 +29282,7 @@
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+    field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -34363,6 +34372,7 @@
 package android.service.notification {
 
   public class Condition implements android.os.Parcelable {
+    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
     method public android.service.notification.Condition copy();
     method public int describeContents();
@@ -34394,7 +34404,6 @@
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
-    method public abstract void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
@@ -43262,7 +43271,7 @@
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
     method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
-    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -43349,7 +43358,7 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.RestrictedCaptionAreaListener {
+  public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
     method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
   }
 
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 2c6729d..0bf6594 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -199,6 +199,14 @@
 
 }
 
+package android.service.notification {
+
+  public abstract class ConditionProviderService extends android.app.Service {
+    method public void onRequestConditions(int);
+  }
+
+}
+
 package android.test.mock {
 
   public deprecated class MockPackageManager extends android.content.pm.PackageManager {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 82170d1..cb29419 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -560,11 +560,13 @@
         }
 
         /**
-         * Returns true if the windows of tasks being moved to this stack should be preserved so
-         * there isn't a display gap.
+         * Returns true if the windows of tasks being moved to the target stack from the source
+         * stack should be replaced, meaning that window manager will keep the old window around
+         * until the new is ready.
          */
-        public static boolean preserveWindowOnTaskMove(int stackId) {
-            return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+        public static boolean replaceWindowsOnTaskMove(int sourceStackId, int targetStackId) {
+            return sourceStackId == FREEFORM_WORKSPACE_STACK_ID
+                    || targetStackId == FREEFORM_WORKSPACE_STACK_ID;
         }
 
         /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 56e4afa..b5b2753 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5080,6 +5080,10 @@
             }
         }
 
+        // Add the lib dir path to hardware renderer so that vulkan layers
+        // can be searched for within that directory.
+        ThreadedRenderer.setLibDir(data.info.getLibDir());
+
         // Install the Network Security Config Provider. This must happen before the application
         // code is loaded to prevent issues with instances of TLS objects being created before
         // the provider is installed.
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index fa0fbd1..04493cb 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -113,4 +113,9 @@
      * Check whether wallpapers are supported for the calling user.
      */
     boolean isWallpaperSupported(in String callingPackage);
+    
+    /**
+     * Check whether setting of wallpapers are allowed for the calling user.
+     */
+    boolean isWallpaperSettingAllowed(in String callingPackage);
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b0ffd21..eda82c0 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -74,7 +74,8 @@
  * {@link #getInstance(android.content.Context) getInstance()}.
  *
  * <p> An app can check whether wallpapers are supported for the current user, by calling
- * {@link #isWallpaperSupported()}.
+ * {@link #isWallpaperSupported()}, and whether setting of wallpapers is allowed, by calling
+ * {@link #isWallpaperSettingAllowed()}.
  */
 public class WallpaperManager {
     private static String TAG = "WallpaperManager";
@@ -134,7 +135,7 @@
      * screen coordinates.
      */
     public static final String COMMAND_TAP = "android.wallpaper.tap";
-    
+
     /**
      * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
      * host when the user releases a secondary pointer on an empty area
@@ -177,7 +178,7 @@
     public static final int FLAG_SET_LOCK = 1 << 1;
 
     private final Context mContext;
-    
+
     /**
      * Special drawable that draws a wallpaper as fast as possible.  Assumes
      * no scaling or placement off (0,0) of the wallpaper (this should be done
@@ -258,19 +259,19 @@
             return mHeight;
         }
     }
-    
+
     static class Globals extends IWallpaperManagerCallback.Stub {
         private IWallpaperManager mService;
         private Bitmap mWallpaper;
         private Bitmap mDefaultWallpaper;
-        
+
         private static final int MSG_CLEAR_WALLPAPER = 1;
-        
+
         Globals(Looper looper) {
             IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
             mService = IWallpaperManager.Stub.asInterface(b);
         }
-        
+
         public void onWallpaperChanged() {
             /* The wallpaper has changed but we shouldn't eagerly load the
              * wallpaper as that would be inefficient. Reset the cached wallpaper
@@ -366,7 +367,7 @@
             return null;
         }
     }
-    
+
     private static final Object sSync = new Object[0];
     private static Globals sGlobals;
 
@@ -377,7 +378,7 @@
             }
         }
     }
-    
+
     /*package*/ WallpaperManager(Context context, Handler handler) {
         mContext = context;
         initGlobals(context.getMainLooper());
@@ -390,18 +391,18 @@
         return (WallpaperManager)context.getSystemService(
                 Context.WALLPAPER_SERVICE);
     }
-    
+
     /** @hide */
     public IWallpaperManager getIWallpaperManager() {
         return sGlobals.mService;
     }
-    
+
     /**
      * Retrieve the current system wallpaper; if
      * no wallpaper is set, the system built-in static wallpaper is returned.
      * This is returned as an
      * abstract Drawable that you can install in a View to display whatever
-     * wallpaper the user has currently set. 
+     * wallpaper the user has currently set.
      *
      * @return Returns a Drawable object that will draw the wallpaper.
      */
@@ -588,7 +589,7 @@
      * Retrieve the current system wallpaper; if there is no wallpaper set,
      * a null pointer is returned. This is returned as an
      * abstract Drawable that you can install in a View to display whatever
-     * wallpaper the user has currently set.  
+     * wallpaper the user has currently set.
      *
      * @return Returns a Drawable object that will draw the wallpaper or a
      * null pointer if these is none.
@@ -641,7 +642,7 @@
 
     /**
      * Like {@link #getDrawable()} but returns a Bitmap.
-     * 
+     *
      * @hide
      */
     public Bitmap getBitmap() {
@@ -1248,7 +1249,7 @@
      * are floating point numbers ranging from 0 to 1, representing where the
      * wallpaper should be positioned within the screen space.  These only
      * make sense when the wallpaper is larger than the display.
-     * 
+     *
      * @param windowToken The window who these offsets should be associated
      * with, as returned by {@link android.view.View#getWindowToken()
      * View.getWindowToken()}.
@@ -1271,17 +1272,17 @@
      * specify the step size between virtual screens. For example, if the
      * launcher has 3 virtual screens, it would specify an xStep of 0.5,
      * since the X offset for those screens are 0.0, 0.5 and 1.0
-     * @param xStep The X offset delta from one screen to the next one 
+     * @param xStep The X offset delta from one screen to the next one
      * @param yStep The Y offset delta from one screen to the next one
      */
     public void setWallpaperOffsetSteps(float xStep, float yStep) {
         mWallpaperXStep = xStep;
         mWallpaperYStep = yStep;
     }
-    
+
     /**
      * Send an arbitrary command to the current active wallpaper.
-     * 
+     *
      * @param windowToken The window who these offsets should be associated
      * with, as returned by {@link android.view.View#getWindowToken()
      * View.getWindowToken()}.
@@ -1306,7 +1307,8 @@
 
     /**
      * Returns whether wallpapers are supported for the calling user. If this function returns
-     * false, any attempts to changing the wallpaper will have no effect.
+     * {@code false}, any attempts to changing the wallpaper will have no effect,
+     * and any attempt to obtain of the wallpaper will return {@code null}.
      */
     public boolean isWallpaperSupported() {
         if (sGlobals.mService == null) {
@@ -1322,11 +1324,31 @@
     }
 
     /**
+     * Returns whether the calling package is allowed to set the wallpaper for the calling user.
+     * If this function returns {@code false}, any attempts to change the wallpaper will have
+     * no effect. Always returns {@code true} for device owner and profile owner.
+     *
+     * @see android.os.UserManager#DISALLOW_SET_WALLPAPER
+     */
+    public boolean isWallpaperSettingAllowed() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+        } else {
+            try {
+                return sGlobals.mService.isWallpaperSettingAllowed(mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        return false;
+    }
+
+    /**
      * Clear the offsets previously associated with this window through
      * {@link #setWallpaperOffsets(IBinder, float, float)}.  This reverts
      * the window to its default state, where it does not cause the wallpaper
      * to scroll from whatever its last offsets were.
-     * 
+     *
      * @param windowToken The window who these offsets should be associated
      * with, as returned by {@link android.view.View#getWindowToken()
      * View.getWindowToken()}.
@@ -1339,7 +1361,7 @@
             // Ignore.
         }
     }
-    
+
     /**
      * Remove any currently set wallpaper, reverting to the system's built-in
      * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 5622207..9f1a9cf0 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -48,7 +48,6 @@
      */
     private final long mEndTimeStamp;
 
-
     /**
      * Non-null array indicates the query enumerates over uids.
      */
@@ -165,7 +164,18 @@
          */
         public static final int ROAMING_ROAMING = 0x2;
 
+        /**
+         * Special TAG value matching any tag.
+         */
+        public static final int TAG_ANY = android.net.NetworkStats.TAG_ALL;
+
+        /**
+         * Special TAG value for total data across all tags
+         */
+        public static final int TAG_ALL = android.net.NetworkStats.TAG_NONE;
+
         private int mUid;
+        private int mTag;
         private int mState;
         private int mRoaming;
         private long mBeginTimeStamp;
@@ -192,6 +202,14 @@
             return uid;
         }
 
+        private static int convertTag(int tag) {
+            switch (tag) {
+                case android.net.NetworkStats.TAG_ALL: return TAG_ANY;
+                case android.net.NetworkStats.TAG_NONE: return TAG_ALL;
+            }
+            return tag;
+        }
+
         private static int convertRoaming(int roaming) {
             switch (roaming) {
                 case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
@@ -218,6 +236,14 @@
         }
 
         /**
+         * Tag of the bucket.<p />
+         * @return Bucket tag.
+         */
+        public int getTag() {
+            return mTag;
+        }
+
+        /**
          * Usage state. One of the following values:<p/>
          * <ul>
          * <li>{@link #STATE_ALL}</li>
@@ -363,9 +389,9 @@
      * Collects summary results and sets summary enumeration mode.
      * @throws RemoteException
      */
-    void startSummaryEnumeration() throws RemoteException {
-        mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, false);
-
+    void startSummaryEnumeration(boolean includeTags) throws RemoteException {
+        mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp,
+                includeTags);
         mEnumerationIndex = 0;
     }
 
@@ -373,10 +399,17 @@
      * Collects history results for uid and resets history enumeration index.
      */
     void startHistoryEnumeration(int uid) {
+        startHistoryEnumeration(uid, android.net.NetworkStats.TAG_NONE);
+    }
+
+    /**
+     * Collects history results for uid and resets history enumeration index.
+     */
+    void startHistoryEnumeration(int uid, int tag) {
         mHistory = null;
         try {
             mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
-                    android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE,
+                    android.net.NetworkStats.SET_ALL, tag,
                     NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
             setSingleUid(uid);
         } catch (RemoteException e) {
@@ -434,6 +467,7 @@
 
     private void fillBucketFromSummaryEntry(Bucket bucketOut) {
         bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
+        bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag);
         bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
         bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
         bucketOut.mBeginTimeStamp = mStartTimeStamp;
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1a9bf4e..4dc636b 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -82,10 +82,11 @@
     }
     /**
      * Query network usage statistics summaries. Result is summarised data usage for the whole
-     * device. Result is a single Bucket aggregated over time, state and uid. This means the
-     * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime'
-     * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
-     * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
+     * means the bucket's start and end timestamp are going to be the same as the 'startTime' and
+     * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
+     * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_ALL}
+     * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -114,11 +115,22 @@
     }
 
     /**
+     * Query network usage statistics summaries aggregated across tags.
+     *
+     * #see querySummaryForUser(int, String, long, long, boolean)
+     */
+    public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
+            long endTime) throws SecurityException, RemoteException {
+        return querySummaryForUser(networkType, subscriberId, startTime, endTime,
+            false /* includeTags */);
+    }
+
+    /**
      * Query network usage statistics summaries. Result is summarised data usage for all uids
      * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
      * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
-     * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
-     * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
+     * {@link NetworkStats.Bucket#UID_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -128,11 +140,13 @@
      *            {@link java.lang.System#currentTimeMillis}.
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
+     * @param includeTags whether to include network tags. If {@code true}, tags will be returned
+     *            and history retention may be shorter.
      * @return Bucket object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
     public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
+            long endTime, boolean includeTags) throws SecurityException, RemoteException {
         NetworkTemplate template = createTemplate(networkType, subscriberId);
         if (template == null) {
             return null;
@@ -140,18 +154,28 @@
 
         NetworkStats stats;
         stats = new NetworkStats(mContext, template, startTime, endTime);
-        stats.startSummaryEnumeration();
+        stats.startSummaryEnumeration(includeTags);
 
         stats.close();
         return stats.getSummaryAggregate();
     }
 
     /**
+     * Query network usage statistics summaries aggregated across tags.
+     *
+     * #see querySummary(int, String, long, long, boolean)
+     */
+    public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
+            long endTime) throws SecurityException, RemoteException {
+        return querySummary(networkType, subscriberId, startTime, endTime, false /* includeTags */);
+    }
+
+    /**
      * Query network usage statistics summaries. Result filtered to include only uids belonging to
      * calling user. Result is aggregated over time, hence all buckets will have the same start and
-     * end timestamps. Not aggregated over state, uid, or roaming. This means buckets' start and end
-     * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and
-     * uid are going to vary.
+     * end timestamps. Not aggregated over state or uid or tag. This means buckets' start and end
+     * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. State,
+     * uid and tag are going to vary.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -161,11 +185,13 @@
      *            {@link java.lang.System#currentTimeMillis}.
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
+     * @param includeTags whether to include network tags. If {@code true}, tags will be returned
+     *            and history retention may be shorter.
      * @return Statistics object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
     public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
+            long endTime, boolean includeTags) throws SecurityException, RemoteException {
         NetworkTemplate template = createTemplate(networkType, subscriberId);
         if (template == null) {
             return null;
@@ -173,17 +199,28 @@
 
         NetworkStats result;
         result = new NetworkStats(mContext, template, startTime, endTime);
-        result.startSummaryEnumeration();
+        result.startSummaryEnumeration(includeTags);
 
         return result;
     }
 
     /**
-     * Query network usage statistics details. Only usable for uids belonging to calling user.
-     * Result is aggregated over state but not aggregated over time. This means buckets' start and
-     * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going
-     * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. roaming
-     * is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * Query network usage statistics details for a given uid.
+     *
+     * #see queryDetailsForUidTag(int, String, long, long, int, int)
+     */
+    public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
+            long startTime, long endTime, int uid) throws SecurityException, RemoteException {
+        return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
+            NetworkStats.Bucket.TAG_ALL);
+    }
+
+    /**
+     * Query network usage statistics details for a given uid and tag. Only usable for uids
+     * belonging to calling user. Result is aggregated over state but not aggregated over time.
+     * This means buckets' start and end timestamps are going to be between 'startTime' and
+     * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
+     * same as the 'uid' parameter and tag the same as 'tag' parameter.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
      * method cannot be used to measure data usage on a fine grained time scale.
@@ -197,11 +234,14 @@
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
      * @param uid UID of app
+     * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_ANY} for any tags, use
+     *            {@link NetworkStats.Bucket#TAG_ALL} to aggregate over tags.
      * @return Statistics object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
-    public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
-            long startTime, long endTime, int uid) throws SecurityException, RemoteException {
+    public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+            long startTime, long endTime, int uid, int tag) throws SecurityException,
+            RemoteException {
         NetworkTemplate template = createTemplate(networkType, subscriberId);
         if (template == null) {
             return null;
@@ -209,7 +249,7 @@
 
         NetworkStats result;
         result = new NetworkStats(mContext, template, startTime, endTime);
-        result.startHistoryEnumeration(uid);
+        result.startHistoryEnumeration(uid, tag);
 
         return result;
     }
@@ -218,8 +258,9 @@
      * Query network usage statistics details. Result filtered to include only uids belonging to
      * calling user. Result is aggregated over state but not aggregated over time or uid. This means
      * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
-     * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary.
-     * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
+     * tag {@link NetworkStats.Bucket#TAG_ALL} and roaming is going to be
+     * {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
      * method cannot be used to measure data usage on a fine grained time scale.
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 3219fe7..55b8f03 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -38,6 +38,7 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.Adapter;
 import android.widget.AdapterView;
@@ -234,6 +235,25 @@
         }
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        try {
+            super.onLayout(changed, left, top, right, bottom);
+        } catch (final RuntimeException e) {
+            Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
+            removeViewInLayout(mView);
+            View child = getErrorView();
+            prepareView(child);
+            addViewInLayout(child, 0, child.getLayoutParams());
+            measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+            child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
+                    child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
+            mView = child;
+            mViewMode = VIEW_MODE_ERROR;
+        }
+    }
+
     /**
      * Provide guidance about the size of this widget to the AppWidgetManager. The widths and
      * heights should correspond to the full area the AppWidgetHostView is given. Padding added by
@@ -381,7 +401,7 @@
                     remoteViews.reapply(mContext, mView, mOnClickHandler);
                     content = mView;
                     recycled = true;
-                    if (LOGD) Log.d(TAG, "was able to recycled existing layout");
+                    if (LOGD) Log.d(TAG, "was able to recycle existing layout");
                 } catch (RuntimeException e) {
                     exception = e;
                 }
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 8919d51..3d8b091 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -49,6 +49,7 @@
     /** {@link #uid} value when UID details unavailable. */
     public static final int UID_ALL = -1;
     /** {@link #tag} value matching any tag. */
+    // TODO: Rename TAG_ALL to TAG_ANY.
     public static final int TAG_ALL = -1;
     /** {@link #set} value for all sets combined, not including debug sets. */
     public static final int SET_ALL = -1;
@@ -64,6 +65,7 @@
     public static final int SET_DBG_VPN_OUT = 1002;
 
     /** {@link #tag} value for total data across all tags. */
+    // TODO: Rename TAG_NONE to TAG_ALL.
     public static final int TAG_NONE = 0;
 
     /** {@link #set} value for all roaming values. */
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index c776ef8..e841dfe 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -479,6 +479,11 @@
     public static String DIRECTORY_DOCUMENTS = "Documents";
 
     /**
+     * Standard directory in which user managed files are stored.
+     */
+    public static String DIRECTORY_HOME = "Home";
+
+    /**
      * List of standard storage directories.
      * <p>
      * Each of its values have its own constant:
@@ -493,6 +498,7 @@
      *   <li>{@link #DIRECTORY_DOWNLOADS}
      *   <li>{@link #DIRECTORY_DCIM}
      *   <li>{@link #DIRECTORY_DOCUMENTS}
+     *   <li>{@link #DIRECTORY_HOME}
      * </ul>
      * @hide
      */
@@ -506,7 +512,8 @@
             DIRECTORY_MOVIES,
             DIRECTORY_DOWNLOADS,
             DIRECTORY_DCIM,
-            DIRECTORY_DOCUMENTS
+            DIRECTORY_DOCUMENTS,
+            DIRECTORY_HOME
     };
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ac798b..ad7b4e2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -463,9 +463,11 @@
     public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
 
     /**
-     * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
-     * is always set for managed profiles.
+     * Hidden user restriction to disallow access to wallpaper manager APIs. This restriction
+     * generally means that wallpapers are not supported for the particular user. This user
+     * restriction is always set for managed profiles, because such profiles don't have wallpapers.
      * @hide
+     * @see #DISALLOW_SET_WALLPAPER
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
@@ -473,6 +475,19 @@
     public static final String DISALLOW_WALLPAPER = "no_wallpaper";
 
     /**
+     * User restriction to disallow setting a wallpaper. Profile owner and device owner
+     * are able to set wallpaper regardless of this restriction.
+     * The default value is <code>false</code>.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
+
+    /**
      * Specifies if the user is not allowed to reboot the device into safe boot mode.
      * This can only be set by device owners and profile owners on the primary user.
      * The default value is <code>false</code>.
@@ -535,9 +550,7 @@
      * affected. The default value is <code>false</code>.
      *
      * <p>Key for user restrictions.
-     *
      * <p>Type: Boolean
-     *
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 2c7bf65..11737c6 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Parcel;
@@ -24,7 +25,8 @@
 import java.util.Objects;
 
 /**
- * Condition information from condition providers.
+ * Condition information from condition providers. Used to tell the system to enter Do Not Disturb
+ * mode and request that the system exit Do Not Disturb mode.
  */
 public class Condition implements Parcelable {
 
@@ -38,14 +40,47 @@
     public static final int FLAG_RELEVANT_NOW = 1 << 0;
     public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
 
+    /**
+     * The URI representing the condition being updated.
+     * See {@link android.app.AutomaticZenRule#getConditionId()}.
+     */
     public final Uri id;
-    public final String summary;
-    public final String line1;
-    public final String line2;
-    public final int icon;
-    public final int state;
-    public final int flags;
 
+    /**
+     * A summary of what the rule encoded in {@link #id} means when it is enabled. User visible
+     * if the state of the condition is {@link #STATE_TRUE}.
+     */
+    public final String summary;
+
+    /**
+     * Additional information about what the rule encoded in {@link #id} means when it is enabled.
+     * User visible if the state of the condition is {@link #STATE_TRUE}.
+     */
+    public final String line1;
+
+    /**
+     * Additional information about what the rule encoded in {@link #id} means when it is enabled.
+     * User visible if the state of the condition is {@link #STATE_TRUE}.
+     */
+    public final String line2;
+
+    /**
+     * The state of this condition. {@link #STATE_TRUE} will enable Do Not Disturb mode. Any other
+     * state will turn Do Not Disturb off for this rule. Note that Do Not Disturb might still be
+     * enabled globally if other conditions are in a {@link #STATE_TRUE} state.
+     */
+    public final int state;
+
+    @SystemApi
+    public final int flags;
+    @SystemApi
+    public final int icon;
+
+    public Condition(Uri id, String summary, String line1, String line2, int state) {
+        this(id, summary, line1, line2, -1, state, FLAG_RELEVANT_ALWAYS);
+    }
+
+    @SystemApi
     public Condition(Uri id, String summary, String line1, String line2, int icon,
             int state, int flags) {
         if (id == null) throw new IllegalArgumentException("id is required");
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index eff09d6..adcc9d6 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -17,6 +17,7 @@
 package android.service.notification;
 
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.app.INotificationManager;
 import android.app.Service;
 import android.content.ComponentName;
@@ -102,13 +103,10 @@
     abstract public void onConnected();
 
     /**
-     * Called when the system wants to know the state of Conditions managed by this provider.
-     *
-     * Implementations should evaluate the state of all subscribed conditions, and provide updates
-     * by calling {@link #notifyCondition(Condition)} or {@link #notifyConditions(Condition...)}.
-     * @param relevance
+     * @removed
      */
-    abstract public void onRequestConditions(int relevance);
+    @SystemApi
+    public void onRequestConditions(int relevance) {}
 
     /**
      * Called by the system when there is a new {@link Condition} to be managed by this provider.
@@ -131,7 +129,11 @@
     }
 
     /**
-     * Informs the notification manager that the state of a Condition has changed.
+     * Informs the notification manager that the state of a Condition has changed. Use this method
+     * to put the system into Do Not Disturb mode or request that it exits Do Not Disturb mode. This
+     * call will be ignored unless there is an enabled {@link android.app.AutomaticZenRule} owned by
+     * service that has an {@link android.app.AutomaticZenRule#getConditionId()} equal to this
+     * {@link Condition#id}.
      * @param condition the condition that has changed.
      */
     public final void notifyCondition(Condition condition) {
@@ -140,7 +142,8 @@
     }
 
     /**
-     * Informs the notification manager that the state of one or more Conditions has changed.
+     * Informs the notification manager that the state of one or more Conditions has changed. See
+     * {@link #notifyCondition(Condition)} for restrictions.
      * @param conditions the changed conditions.
      */
     public final void notifyConditions(Condition... conditions) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 27ea92d..1740f07 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -381,4 +381,9 @@
      * @param receiver The receiver to deliver the results to.
      */
     void requestAppKeyboardShortcuts(IResultReceiver receiver);
+
+    /**
+     * Retrieves the current stable insets from the primary display.
+     */
+    void getStableInsets(out Rect outInsets);
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 78a63a6..8b06ecf 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -252,6 +252,17 @@
     }
 
     /**
+     * Sets the library directory to use as a search path for vulkan layers.
+     *
+     * @param libDir A directory that contains vulkan layers
+     *
+     * @hide
+     */
+    public static void setLibDir(String libDir) {
+        ThreadedRenderer.setupVulkanLayerPath(libDir);
+    }
+
+    /**
      * Creates a hardware renderer using OpenGL.
      *
      * @param translucent True if the surface is translucent, false otherwise
@@ -979,6 +990,7 @@
     }
 
     static native void setupShadersDiskCache(String cacheFile);
+    static native void setupVulkanLayerPath(String layerPath);
 
     private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
     private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 96b63d1..c68a740 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -34,7 +34,6 @@
 import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -273,7 +272,7 @@
     private Callback mCallback;
     private OnWindowDismissedCallback mOnWindowDismissedCallback;
     private WindowControllerCallback mWindowControllerCallback;
-    private RestrictedCaptionAreaListener mRestrictedCaptionAreaListener;
+    private OnRestrictedCaptionAreaChangedListener mOnRestrictedCaptionAreaChangedListener;
     private Rect mRestrictedCaptionAreaRect;
     private WindowManager mWindowManager;
     private IBinder mAppToken;
@@ -596,7 +595,7 @@
     /**
      * Callback for clients that want to be aware of where caption draws content.
      */
-    public interface RestrictedCaptionAreaListener {
+    public interface OnRestrictedCaptionAreaChangedListener {
         /**
          * Called when the area where caption draws content changes.
          *
@@ -856,8 +855,8 @@
      *
      * @param listener Callback that will be called when the area changes.
      */
-    public final void setRestrictedCaptionAreaListener(RestrictedCaptionAreaListener listener) {
-        mRestrictedCaptionAreaListener = listener;
+    public final void setRestrictedCaptionAreaListener(OnRestrictedCaptionAreaChangedListener listener) {
+        mOnRestrictedCaptionAreaChangedListener = listener;
         mRestrictedCaptionAreaRect = listener != null ? new Rect() : null;
     }
 
@@ -2126,17 +2125,20 @@
 
     /** @hide */
     public void notifyRestrictedCaptionAreaCallback(int left, int top, int right, int bottom) {
-        if (mRestrictedCaptionAreaListener != null) {
+        if (mOnRestrictedCaptionAreaChangedListener != null) {
             mRestrictedCaptionAreaRect.set(left, top, right, bottom);
-            mRestrictedCaptionAreaListener.onRestrictedCaptionAreaChanged(
+            mOnRestrictedCaptionAreaChangedListener.onRestrictedCaptionAreaChanged(
                     mRestrictedCaptionAreaRect);
         }
     }
 
     /**
      * Set what color should the caption controls be. By default the system will try to determine
-     * the color from the theme. You can overwrite this by using {@link #DECOR_CAPTION_SHADE_DARK}
-     * or {@link #DECOR_CAPTION_SHADE_DARK}.
+     * the color from the theme. You can overwrite this by using {@link #DECOR_CAPTION_SHADE_DARK},
+     * {@link #DECOR_CAPTION_SHADE_LIGHT}, or {@link #DECOR_CAPTION_SHADE_AUTO}.
+     * @see #DECOR_CAPTION_SHADE_DARK
+     * @see #DECOR_CAPTION_SHADE_LIGHT
+     * @see #DECOR_CAPTION_SHADE_AUTO
      */
     public abstract void setDecorCaptionShade(int decorCaptionShade);
 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index a11897d..5b4a368 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3930,7 +3930,7 @@
         super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
 
         final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+        final boolean isHeading = lp != null && lp.viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
         final boolean isSelected = isItemChecked(position);
         final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
                 position, 1, 0, 1, isHeading, isSelected);
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index c4ec714..478a56d 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.app;
 
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -165,6 +166,14 @@
                     localized.setVisibility(View.VISIBLE);
                     text.setTextLocale(Locale.getDefault());
                 }
+                if (mCountryMode) {
+                    int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
+                    //noinspection ResourceType
+                    convertView.setLayoutDirection(layoutDir);
+                    text.setTextDirection(layoutDir == View.LAYOUT_DIRECTION_RTL
+                            ? View.TEXT_DIRECTION_RTL
+                            : View.TEXT_DIRECTION_LTR);
+                }
         }
         return convertView;
     }
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a38139f..597c522 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -58,6 +58,7 @@
     private final Rect mInsets = new Rect();
     private final int mSnapMode;
     private final float mFixedRatio;
+    private boolean mIsHorizontalDivision;
 
     /** The first target which is still splitting the screen */
     private final SnapTarget mFirstSplitTarget;
@@ -78,6 +79,7 @@
         mDividerSize = dividerSize;
         mDisplayWidth = displayWidth;
         mDisplayHeight = displayHeight;
+        mIsHorizontalDivision = isHorizontalDivision;
         mInsets.set(insets);
         mSnapMode = res.getInteger(
                 com.android.internal.R.integer.config_dockedStackDividerSnapMode);
@@ -130,10 +132,12 @@
 
     public float calculateDismissingFraction(int position) {
         if (position < mFirstSplitTarget.position) {
-            return 1f - (float) position / mFirstSplitTarget.position;
+            return 1f - (float) (position - getStartInset())
+                    / (mFirstSplitTarget.position - getStartInset());
         } else if (position > mLastSplitTarget.position) {
             return (float) (position - mLastSplitTarget.position)
-                    / (mDismissEndTarget.position - mLastSplitTarget.position);
+                    / (mDismissEndTarget.position - getEndInset()
+                            - mLastSplitTarget.position - mDividerSize);
         }
         return 0f;
     }
@@ -167,6 +171,22 @@
         return mDismissEndTarget;
     }
 
+    private int getStartInset() {
+        if (mIsHorizontalDivision) {
+            return mInsets.top;
+        } else {
+            return mInsets.left;
+        }
+    }
+
+    private int getEndInset() {
+        if (mIsHorizontalDivision) {
+            return mInsets.bottom;
+        } else {
+            return mInsets.right;
+        }
+    }
+
     private SnapTarget snap(int position, boolean hardDismiss) {
         int minIndex = -1;
         float minDistance = Float.MAX_VALUE;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8c4683d..ffa3fa6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -184,6 +184,7 @@
     $(LOCAL_PATH)/android/graphics \
     $(LOCAL_PATH)/../../libs/hwui \
     $(LOCAL_PATH)/../../../native/opengl/libs \
+    $(LOCAL_PATH)/../../../native/vulkan/include \
     $(call include-path-for, bluedroid) \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
@@ -233,6 +234,7 @@
     libEGL \
     libGLESv1_CM \
     libGLESv2 \
+    libvulkan \
     libETC1 \
     libhardware \
     libhardware_legacy \
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index edced56..8c907dd 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -27,6 +27,7 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <EGL/egl_cache.h>
+#include <vulkan/vulkan_loader_data.h>
 
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
@@ -618,6 +619,18 @@
 }
 
 // ----------------------------------------------------------------------------
+// Layers
+// ----------------------------------------------------------------------------
+
+static void android_view_ThreadedRenderer_setupVulkanLayerPath(JNIEnv* env, jobject clazz,
+        jstring layerPath) {
+
+    const char* layerArray = env->GetStringUTFChars(layerPath, NULL);
+    vulkan::LoaderData::GetInstance().layer_path = layerArray;
+    env->ReleaseStringUTFChars(layerPath, layerArray);
+}
+
+// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
@@ -658,6 +671,8 @@
     { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
+    { "setupVulkanLayerPath", "(Ljava/lang/String;)V",
+                (void*) android_view_ThreadedRenderer_setupVulkanLayerPath },
     { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index f036b19..40dbe27 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -322,6 +322,19 @@
     }
 
     /**
+     * Insets the rectangle on all sides specified by the dimensions of the {@code insets}
+     * rectangle.
+     * @hide
+     * @param insets The rectangle specifying the insets on all side.
+     */
+    public void inset(Rect insets) {
+        left += insets.left;
+        top += insets.top;
+        right -= insets.right;
+        bottom -= insets.bottom;
+    }
+
+    /**
      * Returns true if (x,y) is inside the rectangle. The left and top are
      * considered to be inside, while the right and bottom are not. This means
      * that for a x,y to be contained: left <= x < right and top <= y < bottom.
diff --git a/include/androidfw/LocaleData.h b/include/androidfw/LocaleData.h
index add0ab5..b14829d 100644
--- a/include/androidfw/LocaleData.h
+++ b/include/androidfw/LocaleData.h
@@ -29,6 +29,8 @@
 
 void localeDataComputeScript(char out[4], const char* language, const char* region);
 
+bool localeDataIsCloseToUsEnglish(const char* region);
+
 } // namespace android
 
 #endif // _LIBS_UTILS_LOCALE_DATA_H
diff --git a/libs/androidfw/LocaleData.cpp b/libs/androidfw/LocaleData.cpp
index c0c3ab8..038ef58 100644
--- a/libs/androidfw/LocaleData.cpp
+++ b/libs/androidfw/LocaleData.cpp
@@ -70,13 +70,17 @@
 //
 // Returns the number of ancestors written in the output, which is always
 // at least one.
+//
+// (If 'out' is nullptr, we do everything the same way but we simply don't write
+// any results in 'out'.)
 size_t findAncestors(uint32_t* out, ssize_t* stop_list_index,
                      uint32_t packed_locale, const char* script,
                      const uint32_t* stop_list, size_t stop_set_length) {
     uint32_t ancestor = packed_locale;
     size_t count = 0;
     do {
-        out[count++] = ancestor;
+        if (out != nullptr) out[count] = ancestor;
+        count++;
         for (size_t i = 0; i < stop_set_length; i++) {
             if (stop_list[i] == ancestor) {
                 *stop_list_index = (ssize_t) i;
@@ -93,10 +97,9 @@
                     const char* script,
                     const uint32_t* request_ancestors,
                     size_t request_ancestors_count) {
-    uint32_t supported_ancestors[MAX_PARENT_DEPTH+1];
     ssize_t request_ancestors_index;
     const size_t supported_ancestor_count = findAncestors(
-            supported_ancestors, &request_ancestors_index,
+            nullptr, &request_ancestors_index,
             supported, script,
             request_ancestors, request_ancestors_count);
     // Since both locales share the same root, there will always be a shared
@@ -198,4 +201,19 @@
     }
 }
 
+const uint32_t ENGLISH_STOP_LIST[2] = {
+    0x656E0000lu, // en
+    0x656E8400lu, // en-001
+};
+const char ENGLISH_CHARS[2] = {'e', 'n'};
+const char LATIN_CHARS[4] = {'L', 'a', 't', 'n'};
+
+bool localeDataIsCloseToUsEnglish(const char* region) {
+    const uint32_t locale = packLocale(ENGLISH_CHARS, region);
+    ssize_t stop_list_index;
+    findAncestors(nullptr, &stop_list_index, locale, LATIN_CHARS, ENGLISH_STOP_LIST, 2);
+    // A locale is like US English if we see "en" before "en-001" in its ancestor list.
+    return stop_list_index == 0; // 'en' is first in ENGLISH_STOP_LIST
+}
+
 } // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 71e9c92..1d9fe35 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2196,7 +2196,32 @@
         // The languages of the two resources are not the same. We can only
         // assume that one of the two resources matched the request because one
         // doesn't have a language and the other has a matching language.
-        return (language[0] != 0);
+        //
+        // We consider the one that has the language specified a better match.
+        //
+        // The exception is that we consider no-language resources a better match
+        // for US English and similar locales than locales that are a descendant
+        // of Internatinal English (en-001), since no-language resources are
+        // where the US English resource have traditionally lived for most apps.
+        if (requested->language[0] == 'e' && requested->language[1] == 'n') {
+            if (requested->country[0] == 'U' && requested->country[1] == 'S') {
+                // For US English itself, we consider a no-locale resource a
+                // better match if the other resource has a country other than
+                // US specified.
+                if (language[0] != '\0') {
+                    return country[0] == '\0' || (country[0] == 'U' && country[1] == 'S');
+                } else {
+                    return !(o.country[0] == '\0' || (o.country[0] == 'U' && o.country[1] == 'S'));
+                }
+            } else if (localeDataIsCloseToUsEnglish(requested->country)) {
+                if (language[0] != '\0') {
+                    return localeDataIsCloseToUsEnglish(country);
+                } else {
+                    return !localeDataIsCloseToUsEnglish(o.country);
+                }
+            }
+        }
+        return (language[0] != '\0');
     }
 
     // If we are here, both the resources have the same non-empty language as
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 1941563..7b38640 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -592,4 +592,52 @@
     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
 }
 
+// Default resources are considered better matches for US English
+// and US-like English locales than International English locales
+TEST(ConfigLocaleTest, isLocaleBetterThan_UsEnglishIsSpecial) {
+    ResTable_config config1, config2, request;
+
+    fillIn("en", "US", NULL, NULL, &request);
+    fillIn(NULL, NULL, NULL, NULL, &config1);
+    fillIn("en", "001", NULL, NULL, &config2);
+    // default is better than International English
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "US", NULL, NULL, &request);
+    fillIn(NULL, NULL, NULL, NULL, &config1);
+    fillIn("en", "GB", NULL, NULL, &config2);
+    // default is better than British English
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "PR", NULL, NULL, &request);
+    fillIn(NULL, NULL, NULL, NULL, &config1);
+    fillIn("en", "001", NULL, NULL, &config2);
+    // Even for Puerto Rico, default is better than International English
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "US", NULL, NULL, &request);
+    fillIn("en", NULL, NULL, NULL, &config1);
+    fillIn(NULL, NULL, NULL, NULL, &config2);
+    // "English" is better than default, since it's a parent of US English
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "PR", NULL, NULL, &request);
+    fillIn("en", NULL, NULL, NULL, &config1);
+    fillIn(NULL, NULL, NULL, NULL, &config2);
+    // "English" is better than default, since it's a parent of Puerto Rico English
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "US", NULL, NULL, &request);
+    fillIn(NULL, NULL, NULL, NULL, &config1);
+    fillIn("en", "PR", NULL, NULL, &config2);
+    // For US English itself, we prefer default to its siblings in the parent tree
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+}
+
 }  // namespace android
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 71e87cb..eea91a0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -129,9 +129,11 @@
 
                     @Override
                     public void onChanged() {
-                        // TODO: This is causing b/22765812
-                        mSelection.clear();
                         mModelIds = mAdapter.getModelIds();
+
+                        // Update the selection to remove any disappeared IDs.
+                        mSelection.cancelProvisionalSelection();
+                        mSelection.intersect(mModelIds);
                     }
 
                     @Override
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 1bfc19c..56e5a9b 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -27,6 +27,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.Environment;
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -208,8 +209,10 @@
                 root.flags |= Root.FLAG_SUPPORTS_CREATE;
             }
 
+            // Create the "Home" directory on disk, but don't the localized root.title
+            // since the directories shouldn't be localized.
             root.visiblePath = new File(
-                    primaryVolume.getPathForUser(userId), root.rootId);
+                    primaryVolume.getPathForUser(userId), Environment.DIRECTORY_HOME);
             root.path = new File(
                     primaryVolume.getInternalPathForUser(userId), root.rootId);
             try {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 743df99..892be2d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -167,6 +167,8 @@
 
     public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
 
+    private boolean mIsOptionsUiBound = false;
+
     private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
             new PrinterAvailabilityDetector();
 
@@ -337,7 +339,7 @@
     @Override
     public void onStart() {
         super.onStart();
-        if (mState != STATE_INITIALIZING && mCurrentPrinter != null) {
+        if (mPrinterRegistry != null && mCurrentPrinter != null) {
             mPrinterRegistry.setTrackedPrinter(mCurrentPrinter.getId());
         }
         MetricsLogger.count(this, "print_preview", 1);
@@ -384,7 +386,10 @@
     @Override
     protected void onStop() {
         mPrinterAvailabilityDetector.cancel();
-        mPrinterRegistry.setTrackedPrinter(null);
+
+        if (mPrinterRegistry != null) {
+            mPrinterRegistry.setTrackedPrinter(null);
+        }
 
         super.onStop();
     }
@@ -1214,6 +1219,9 @@
         mPrintButton = (ImageView) findViewById(R.id.print_button);
         mPrintButton.setOnClickListener(clickListener);
 
+        // The UI is now initialized
+        mIsOptionsUiBound = true;
+
         // Special prompt instead of destination spinner for the first time the user printed
         if (!hasUserEverPrinted()) {
             mShowDestinationPrompt = true;
@@ -1390,6 +1398,10 @@
     }
 
     void updateOptionsUi() {
+        if (!mIsOptionsUiBound) {
+            return;
+        }
+
         // Always update the summary.
         updateSummary();
 
@@ -1725,6 +1737,10 @@
     }
 
     private void updateSummary() {
+        if (!mIsOptionsUiBound) {
+            return;
+        }
+
         CharSequence copiesText = null;
         CharSequence mediaSizeText = null;
 
@@ -1912,9 +1928,12 @@
     }
 
     private void doFinish() {
+        if (mPrinterRegistry != null) {
+            mPrinterRegistry.setTrackedPrinter(null);
+        }
+
         if (mState != STATE_INITIALIZING) {
             mProgressMessageController.cancel();
-            mPrinterRegistry.setTrackedPrinter(null);
             mSpoolerProvider.destroy();
             mPrintedDocument.finish();
             mPrintedDocument.destroy();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7ee53a2..c075703 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -835,7 +835,7 @@
     public int getConnectionSummary() {
         boolean profileConnected = false;       // at least one profile is connected
         boolean a2dpNotConnected = false;       // A2DP is preferred but not connected
-        boolean headsetNotConnected = false;    // Headset is preferred but not connected
+        boolean hfpNotConnected = false;    // HFP is preferred but not connected
 
         for (LocalBluetoothProfile profile : getProfiles()) {
             int connectionStatus = getProfileConnectionState(profile);
@@ -851,11 +851,12 @@
 
                 case BluetoothProfile.STATE_DISCONNECTED:
                     if (profile.isProfileReady()) {
-                        if ((profile instanceof A2dpProfile)||
+                        if ((profile instanceof A2dpProfile) ||
                             (profile instanceof A2dpSinkProfile)){
                             a2dpNotConnected = true;
-                        } else if (profile instanceof HeadsetProfile) {
-                            headsetNotConnected = true;
+                        } else if ((profile instanceof HeadsetProfile) ||
+                                   (profile instanceof HfpClientProfile)) {
+                            hfpNotConnected = true;
                         }
                     }
                     break;
@@ -863,11 +864,11 @@
         }
 
         if (profileConnected) {
-            if (a2dpNotConnected && headsetNotConnected) {
+            if (a2dpNotConnected && hfpNotConnected) {
                 return R.string.bluetooth_connected_no_headset_no_a2dp;
             } else if (a2dpNotConnected) {
                 return R.string.bluetooth_connected_no_a2dp;
-            } else if (headsetNotConnected) {
+            } else if (hfpNotConnected) {
                 return R.string.bluetooth_connected_no_headset;
             } else {
                 return R.string.bluetooth_connected;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
new file mode 100755
index 0000000..9b699bc
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Handles the Handsfree HF role.
+ */
+final class HfpClientProfile implements LocalBluetoothProfile {
+    private static final String TAG = "HfpClientProfile";
+    private static boolean V = false;
+
+    private BluetoothHeadsetClient mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SRC_UUIDS = {
+        BluetoothUuid.HSP_AG,
+        BluetoothUuid.Handsfree_AG,
+    };
+
+    static final String NAME = "HEADSET_CLIENT";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 0;
+
+    // These callbacks run on the main thread.
+    private final class HfpClientServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothHeadsetClient) proxy;
+            // We just bound to the service, so refresh the UI for any connected HFP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "HfpClient profile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(
+                    HfpClientProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    @Override
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    HfpClientProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new HfpClientServiceListener(),
+                BluetoothProfile.HEADSET_CLIENT);
+    }
+
+    @Override
+    public boolean isConnectable() {
+        return true;
+    }
+
+    @Override
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    @Override
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> srcs = getConnectedDevices();
+        if (srcs != null) {
+            for (BluetoothDevice src : srcs) {
+                if (src.equals(device)) {
+                    // Connect to same device, Ignore it
+                    Log.d(TAG,"Ignoring Connect");
+                    return true;
+                }
+            }
+            // Handsfree HF only supports one source connection and hence it is OK to disconnect
+            // the only connected device here.
+            for (BluetoothDevice src : srcs) {
+                mService.disconnect(src);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    @Override
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        // Downgrade priority as user is disconnecting the headset.
+        if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+            mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+        }
+        return mService.disconnect(device);
+    }
+
+    @Override
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    @Override
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    @Override
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    @Override
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return NAME;
+    }
+
+    @Override
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    @Override
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_headset;
+    }
+
+    @Override
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_headset_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_headset_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    @Override
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headset_hfp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+                    BluetoothProfile.HEADSET_CLIENT, mService);
+                mService = null;
+            } catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up HfpClient proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index b05e34c..6226b23 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothA2dpSink;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothMap;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
@@ -76,6 +77,7 @@
     private A2dpProfile mA2dpProfile;
     private A2dpSinkProfile mA2dpSinkProfile;
     private HeadsetProfile mHeadsetProfile;
+    private HfpClientProfile mHfpClientProfile;
     private MapProfile mMapProfile;
     private final HidProfile mHidProfile;
     private OppProfile mOppProfile;
@@ -150,6 +152,7 @@
             Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
         }
 
+        // A2DP SINK
         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
             if (mA2dpSinkProfile == null) {
                 if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
@@ -175,6 +178,22 @@
             Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
         }
 
+        // Headset HF
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) {
+            if (mHfpClientProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local HfpClient profile");
+                mHfpClientProfile =
+                    new HfpClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
+                addProfile(mHfpClientProfile, HfpClientProfile.NAME,
+                        BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mHfpClientProfile != null) {
+            Log.w(TAG,
+                "Warning: Hfp Client profile was previously added but the UUID is now missing.");
+        } else {
+            Log.d(TAG, "Handsfree Uuid not found.");
+        }
+
         // OPP
         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
             if (mOppProfile == null) {
@@ -312,17 +331,26 @@
         return mA2dpProfile;
     }
 
-    A2dpSinkProfile getA2dpSinkProfile() {
-        if ((mA2dpSinkProfile != null)&&(mA2dpSinkProfile.isProfileReady()))
-        return mA2dpSinkProfile;
-        else
+    public A2dpSinkProfile getA2dpSinkProfile() {
+        if ((mA2dpSinkProfile != null) && (mA2dpSinkProfile.isProfileReady())) {
+            return mA2dpSinkProfile;
+        } else {
             return null;
+        }
     }
 
     public HeadsetProfile getHeadsetProfile() {
         return mHeadsetProfile;
     }
 
+    public HfpClientProfile getHfpClientProfile() {
+        if ((mHfpClientProfile != null) && (mHfpClientProfile.isProfileReady())) {
+            return mHfpClientProfile;
+        } else {
+          return null;
+        }
+    }
+
     public PbapServerProfile getPbapProfile(){
         return mPbapProfile;
     }
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_car.xml b/packages/SystemUI/res/values-pt-rBR/strings_car.xml
index 072f614..5d754ef 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_car.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_car.xml
@@ -20,5 +20,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Dirija com segurança"</string>
-    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições de direção e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições da estrada  e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings_car.xml b/packages/SystemUI/res/values-pt/strings_car.xml
index 072f614..5d754ef 100644
--- a/packages/SystemUI/res/values-pt/strings_car.xml
+++ b/packages/SystemUI/res/values-pt/strings_car.xml
@@ -20,5 +20,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Dirija com segurança"</string>
-    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições de direção e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições da estrada  e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</string>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 32da3c6..c6c448d0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -897,10 +897,10 @@
     <!-- Message for add user confirmation dialog - short version. [CHAR LIMIT=none] -->
     <string name="user_add_user_message_short" msgid="1511354412249044381">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string>
 
-    <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
+    <!-- Title of the confirmation dialog for deleting a user [CHAR LIMIT=NONE] -->
     <string name="user_remove_user_title">Remove user?</string>
 
-    <!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
+    <!-- Message of the confirmation dialog for deleting a user [CHAR LIMIT=NONE] -->
     <string name="user_remove_user_message">All apps and data of this user will be deleted.</string>
 
     <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 0115f91..9e43bb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -103,12 +103,9 @@
     /**
      * Updates the configuration based on the current state of the system
      */
-    void update(Rect windowRect) {
-        // Recompute some values based on the given state, since we can not rely on the resource
-        // system to get certain values.
-        boolean isLandscape = windowRect.width() > windowRect.height();
-        hasTransposedNavBar = isLandscape && !isXLargeScreen;
-        hasTransposedSearchBar = isLandscape && !isXLargeScreen;
+    void update(Rect systemInsets) {
+        hasTransposedNavBar = systemInsets.right > 0;
+        hasTransposedSearchBar = systemInsets.right > 0;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 5a60a19..1cceef4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -599,10 +599,14 @@
             TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
         SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect systemInsets = new Rect();
+        ssp.getStableInsets(systemInsets);
         Rect windowRect = ssp.getWindowRect();
+        calculateWindowStableInsets(systemInsets, windowRect);
+        windowRect.offsetTo(0, 0);
 
         // Update the configuration for the current state
-        config.update(windowRect);
+        config.update(systemInsets);
 
         if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
             // Try and pre-emptively bind the search widget on startup to ensure that we
@@ -612,9 +616,6 @@
                 config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
             }
         }
-        Rect systemInsets = new Rect(0, mStatusBarHeight,
-                (config.hasTransposedNavBar ? mNavBarWidth : 0),
-                (config.hasTransposedNavBar ? 0 : mNavBarHeight));
         config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
                 mSearchBarBounds, mTaskStackBounds);
 
@@ -641,6 +642,26 @@
     }
 
     /**
+     * Given the stable insets and the rect for our window, calculates the insets that affect our
+     * window.
+     */
+    private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect) {
+        Rect displayRect = Recents.getSystemServices().getDisplayRect();
+
+        // Display rect without insets - available app space
+        Rect appRect = new Rect(displayRect);
+        appRect.inset(inOutInsets);
+
+        // Our window intersected with available app space
+        Rect windowRectWithInsets = new Rect(windowRect);
+        windowRectWithInsets.intersect(appRect);
+        inOutInsets.left = windowRectWithInsets.left - windowRect.left;
+        inOutInsets.top = windowRectWithInsets.top - windowRect.top;
+        inOutInsets.right = windowRect.right - windowRectWithInsets.right;
+        inOutInsets.bottom = windowRect.bottom - windowRectWithInsets.bottom;
+    }
+
+    /**
      * Preloads the icon of a task.
      */
     private void preloadIcon(ActivityManager.RunningTaskInfo task) {
@@ -721,8 +742,9 @@
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 Task task = tasks.get(i);
                 if (task.isFreeformTask()) {
-                    mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
-                            stackView.getScroller().getStackScroll(), mTmpTransform, null);
+                    mTmpTransform = stackView.getStackAlgorithm()
+                            .getStackTransformScreenCoordinates(task,
+                                    stackView.getScroller().getStackScroll(), mTmpTransform, null);
                     Rect toTaskRect = new Rect();
                     mTmpTransform.rect.round(toTaskRect);
                     Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
@@ -783,7 +805,7 @@
 
         // Get the transform for the running task
         stackView.getScroller().setStackScrollToInitialState();
-        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(launchTask,
+        mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index d22cd53..22ab794 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -47,6 +47,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -977,6 +978,16 @@
         mWm.requestAppKeyboardShortcuts(receiver);
     }
 
+    public void getStableInsets(Rect outStableInsets) {
+        if (mWm == null) return;
+
+        try {
+            WindowManagerGlobal.getWindowManagerService().getStableInsets(outStableInsets);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
     public void focusPinnedStack() {
         try {
             mIam.setFocusedStack(PINNED_STACK_ID);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 3fdd771..6c1ff9b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -270,7 +270,8 @@
             if (taskView == null) {
                 specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
             } else {
-                layoutAlgorithm.getStackTransform(task, stackScroll, mTmpTransform, null);
+                layoutAlgorithm.getStackTransformScreenCoordinates(task, stackScroll, mTmpTransform,
+                        null);
                 specs.add(composeAnimationSpec(taskView, mTmpTransform, true /* addHeaderBitmap */));
             }
             return specs;
@@ -290,7 +291,8 @@
                     //       never happen)
                     specs.add(composeOffscreenAnimationSpec(t, offscreenTaskRect));
                 } else {
-                    layoutAlgorithm.getStackTransform(t, stackScroll, mTmpTransform, null);
+                    layoutAlgorithm.getStackTransformScreenCoordinates(t, stackScroll,
+                            mTmpTransform, null);
                     specs.add(composeAnimationSpec(tv, mTmpTransform, true /* addHeaderBitmap */));
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 7c695ce..46fdb2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -616,6 +616,18 @@
     }
 
     /**
+     * Like {@link #getStackTransform}, but in screen coordinates
+     */
+    public TaskViewTransform getStackTransformScreenCoordinates(Task task, float stackScroll,
+            TaskViewTransform transformOut, TaskViewTransform frontTransform) {
+        Rect windowRect = Recents.getSystemServices().getWindowRect();
+        TaskViewTransform transform = getStackTransform(task, stackScroll, transformOut,
+                frontTransform);
+        transform.rect.offset(windowRect.left, windowRect.top);
+        return transform;
+    }
+
+    /**
      * Update/get the transform.
      *
      * @param ignoreSingleTaskCase When set, will ensure that the transform computed does not take
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 0b20f7a..1e11fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -184,8 +184,17 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
-                insets.getStableInsetRight(), insets.getStableInsetBottom());
+        if (mStableInsets.left != insets.getStableInsetLeft()
+                || mStableInsets.top != insets.getStableInsetTop()
+                || mStableInsets.right != insets.getStableInsetRight()
+                || mStableInsets.bottom != insets.getStableInsetBottom()) {
+            mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                    insets.getStableInsetRight(), insets.getStableInsetBottom());
+            if (mSnapAlgorithm != null) {
+                mSnapAlgorithm = null;
+                getSnapAlgorithm();
+            }
+        }
         return super.onApplyWindowInsets(insets);
     }
 
@@ -496,12 +505,42 @@
         } else {
             mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
         }
+        SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position);
+        float dimFraction = getDimFraction(position, closestDismissTarget);
+        mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
+                getStackIdForDismissTarget(closestDismissTarget),
+                dimFraction);
+    }
+
+    private float getDimFraction(int position, SnapTarget dismissTarget) {
         float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
         fraction = Math.max(0, Math.min(fraction, 1f));
         fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
-        mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
-                getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
-                fraction);
+        if (hasInsetsAtDismissTarget(dismissTarget)) {
+
+            // Less darkening with system insets.
+            fraction *= 0.8f;
+        }
+        return fraction;
+    }
+
+    /**
+     * @return true if and only if there are system insets at the location of the dismiss target
+     */
+    private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) {
+        if (isHorizontalDivision()) {
+            if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
+                return mStableInsets.top != 0;
+            } else {
+                return mStableInsets.bottom != 0;
+            }
+        } else {
+            if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
+                return mStableInsets.left != 0;
+            } else {
+                return mStableInsets.right != 0;
+            }
+        }
     }
 
     /**
@@ -587,7 +626,7 @@
         }
         if (dismissTarget != null && fraction > 0f
                 && isDismissing(splitTarget, position, dockSide)) {
-            fraction = calculateParallaxDismissingFraction(fraction);
+            fraction = calculateParallaxDismissingFraction(fraction, dockSide);
             int offsetPosition = (int) (taskPosition +
                     fraction * (dismissTarget.position - splitTarget.position));
             int width = taskRect.width();
@@ -617,8 +656,14 @@
      * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
      *         slowing down parallax effect
      */
-    private static float calculateParallaxDismissingFraction(float fraction) {
-        return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+    private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
+        float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+
+        // Less parallax at the top, just because.
+        if (dockSide == WindowManager.DOCKED_TOP) {
+            result /= 2f;
+        }
+        return result;
     }
 
     private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java
new file mode 100644
index 0000000..f9afc7c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import android.content.Context;
+import android.content.DialogInterface;
+
+import com.android.systemui.R;
+
+public class UserUtil {
+    public static void deleteUserWithPrompt(Context context, int userId,
+                                            UserSwitcherController userSwitcherController) {
+        new RemoveUserDialog(context, userId, userSwitcherController).show();
+    }
+
+    private final static class RemoveUserDialog extends SystemUIDialog implements
+            DialogInterface.OnClickListener {
+
+        private final int mUserId;
+        private final UserSwitcherController mUserSwitcherController;
+
+        public RemoveUserDialog(Context context, int userId,
+                                UserSwitcherController userSwitcherController) {
+            super(context);
+            setTitle(R.string.user_remove_user_title);
+            setMessage(context.getString(R.string.user_remove_user_message));
+            setButton(DialogInterface.BUTTON_NEGATIVE,
+                    context.getString(android.R.string.cancel), this);
+            setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(R.string.user_remove_user_remove), this);
+            setCanceledOnTouchOutside(false);
+            mUserId = userId;
+            mUserSwitcherController = userSwitcherController;
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            if (which == BUTTON_NEGATIVE) {
+                cancel();
+            } else {
+                dismiss();
+                mUserSwitcherController.removeUserId(mUserId);
+            }
+        }
+    }
+}
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 28f4e05..2294931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.car;
 
 import android.content.Context;
-import android.content.DialogInterface;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -29,8 +28,8 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.UserUtil;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 public class UserGridView extends GridView {
@@ -88,7 +87,8 @@
                     return true;
                 }
 
-                new RemoveUserDialog(getContext(), record.info.id).show();
+                UserUtil.deleteUserWithPrompt(getContext(), record.info.id,
+                        mUserSwitcherController);
                 return true;
             }
         });
@@ -159,32 +159,4 @@
             return convertView;
         }
     }
-
-    private final class RemoveUserDialog extends SystemUIDialog implements
-            DialogInterface.OnClickListener {
-
-        private final int mUserId;
-
-        public RemoveUserDialog(Context context, int userId) {
-            super(context);
-            setTitle(R.string.user_remove_user_title);
-            setMessage(context.getString(R.string.user_remove_user_message));
-            setButton(DialogInterface.BUTTON_NEGATIVE,
-                    context.getString(android.R.string.cancel), this);
-            setButton(DialogInterface.BUTTON_POSITIVE,
-                    context.getString(R.string.user_remove_user_remove), this);
-            setCanceledOnTouchOutside(false);
-            mUserId = userId;
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            if (which == BUTTON_NEGATIVE) {
-                cancel();
-            } else {
-                dismiss();
-                mUserSwitcherController.removeUserId(mUserId);
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 277668f..575eda7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -93,7 +93,7 @@
     public static final long DOZE_ANIMATION_DURATION = 700;
 
     private KeyguardAffordanceHelper mAfforanceHelper;
-    private BaseStatusBarHeader mHeader;
+    protected BaseStatusBarHeader mHeader;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
     private QSContainer mQsContainer;
@@ -2404,7 +2404,7 @@
         setVerticalPanelTranslation(0f);
     }
 
-    private void setVerticalPanelTranslation(float translation) {
+    protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
         mScrollView.setTranslationX(translation);
         mHeader.setTranslationX(translation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6d51869..07dc4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -795,7 +795,7 @@
                 mKeyguardBottomArea.getLockIcon());
         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
 
-        // set the inital view visibility
+        // set the initial view visibility
         setAreThereNotifications();
 
         mIconController = new StatusBarIconController(
@@ -2339,8 +2339,6 @@
 
     }
 
-    Animator mScrollViewAnim, mClearButtonAnim;
-
     @Override
     public void animateExpandNotificationsPanel() {
         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index db901aa..29801b3 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -46,7 +46,6 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -86,6 +85,7 @@
 import com.android.internal.widget.IRemoteViewsFactory;
 import com.android.server.LocalServices;
 import com.android.server.WidgetBackupProvider;
+import com.android.server.policy.IconUtilities;
 
 import libcore.io.IoUtils;
 
@@ -104,6 +104,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -155,9 +156,17 @@
             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                 onUserStopped(userId);
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                refreshProfileWidgetsMaskedState(userId);
+                reloadWidgetsMaskedStateForUser(userId);
             } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
-                refreshWidgetMaskedState(userId);
+                synchronized (mLock) {
+                    reloadWidgetQuietModeMaskedStateLocked(userId);
+                }
+            } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
+                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                updateWidgetPackageSuspensionMaskedState(packages, true, getSendingUserId());
+            } else if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(action)) {
+                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                updateWidgetPackageSuspensionMaskedState(packages, false, getSendingUserId());
             } else {
                 onPackageBroadcastReceived(intent, userId);
             }
@@ -206,6 +215,8 @@
     private boolean mSafeMode;
     private int mMaxWidgetBitmapMemory;
 
+    private final IconUtilities mIconUtilities;
+
     AppWidgetServiceImpl(Context context) {
         mContext = context;
         mPackageManager = AppGlobals.getPackageManager();
@@ -216,6 +227,7 @@
         mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
         mBackupRestoreController = new BackupRestoreController();
         mSecurityPolicy = new SecurityPolicy();
+        mIconUtilities = new IconUtilities(context);
 
         computeMaximumWidgetBitmapMemory();
         registerBroadcastReceiver();
@@ -268,6 +280,12 @@
         offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
                 offModeFilter, null, null);
+
+        IntentFilter suspendPackageFilter = new IntentFilter();
+        suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                suspendPackageFilter, null, null);
     }
 
     private void registerOnCrossProfileProvidersChangedListener() {
@@ -413,15 +431,20 @@
     }
 
     /**
-     * Refresh the masked state for all profiles under the given user.
+     * Reload all widgets' masked state for the given user and its associated profiles, including
+     * due to quiet mode and package suspension.
      */
-    private void refreshProfileWidgetsMaskedState(int userId) {
+    private void reloadWidgetsMaskedStateForUser(int userId) {
         if (!mUserManager.isUserUnlocked(userId)) return;
-        List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
-        if (profiles != null) {
-            for (int i = 0; i < profiles.size(); i++) {
-                UserInfo user  = profiles.get(i);
-                refreshWidgetMaskedState(user.id);
+        synchronized (mLock) {
+            reloadWidgetPackageSuspensionMaskedStateLocked(userId);
+            List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
+            if (profiles != null) {
+                for (int i = 0; i < profiles.size(); i++) {
+                    UserInfo user  = profiles.get(i);
+                    reloadWidgetQuietModeMaskedStateLocked(user.id);
+                    reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
+                }
             }
         }
     }
@@ -429,7 +452,7 @@
     /**
      * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
      */
-    private void refreshWidgetMaskedState(int profileId) {
+    private void reloadWidgetQuietModeMaskedStateLocked(int profileId) {
         if (!mUserManager.isUserUnlocked(profileId)) return;
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -438,25 +461,18 @@
                 return;
             }
             boolean shouldMask = user.isQuietModeEnabled();
-            final int iconSize = (int) mContext.getResources().getDimension(
-                    android.R.dimen.app_icon_size);
-            synchronized (mLock) {
-                final int N = mProviders.size();
-                for (int i = 0; i < N; i++) {
-                    Provider provider = mProviders.get(i);
-                    int providerUserId = provider.getUserId();
-                    if (providerUserId == profileId) {
-                        final int widgetCount = provider.widgets.size();
-                        for (int j = 0; j < widgetCount; j++) {
-                            Widget widget = provider.widgets.get(j);
-                            if (shouldMask) {
-                                widget.replaceWithMaskedViewsLocked(mContext, iconSize);
-                            } else {
-                                widget.clearMaskedViewsLocked();
-                            }
-                            scheduleNotifyUpdateAppWidgetLocked(widget,
-                                    widget.getEffectiveViewsLocked());
-                        }
+            final int N = mProviders.size();
+            for (int i = 0; i < N; i++) {
+                Provider provider = mProviders.get(i);
+                int providerUserId = provider.getUserId();
+                if (providerUserId != profileId) {
+                    continue;
+                }
+                if (provider.setMaskedByQuietProfileLocked(shouldMask)) {
+                    if (provider.isMaskedLocked()) {
+                        maskWidgetsViewsLocked(provider);
+                    } else {
+                        unmaskWidgetsViewsLocked(provider);
                     }
                 }
             }
@@ -465,6 +481,103 @@
         }
     }
 
+    /**
+     * Reload widget's masked state due to package suspension state.
+     */
+    private void reloadWidgetPackageSuspensionMaskedStateLocked(int profileId) {
+        final int N = mProviders.size();
+        for (int i = 0; i < N; i++) {
+            Provider provider = mProviders.get(i);
+            int providerUserId = provider.getUserId();
+            if (providerUserId != profileId) {
+                continue;
+            }
+            try {
+                ApplicationInfo ai = mPackageManager.getApplicationInfo(
+                        provider.info.provider.getPackageName(), 0, provider.getUserId());
+                boolean suspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+                if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
+                    if (provider.isMaskedLocked()) {
+                        maskWidgetsViewsLocked(provider);
+                    } else {
+                        unmaskWidgetsViewsLocked(provider);
+                    }
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to query application info", e);
+            }
+        }
+    }
+
+    /**
+     * Incrementally update the masked state due to package suspension state.
+     */
+    private void updateWidgetPackageSuspensionMaskedState(String[] packagesArray, boolean suspended,
+            int profileId) {
+        if (packagesArray == null) {
+            return;
+        }
+        Set<String> packages = new ArraySet<String>(Arrays.asList(packagesArray));
+        synchronized (mLock) {
+            final int N = mProviders.size();
+            for (int i = 0; i < N; i++) {
+                Provider provider = mProviders.get(i);
+                int providerUserId = provider.getUserId();
+                if (providerUserId != profileId
+                        || !packages.contains(provider.info.provider.getPackageName())) {
+                    continue;
+                }
+                if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
+                    if (provider.isMaskedLocked()) {
+                        maskWidgetsViewsLocked(provider);
+                    } else {
+                        unmaskWidgetsViewsLocked(provider);
+                    }
+                }
+            }
+        }
+    }
+
+    private void maskWidgetsViewsLocked(Provider provider) {
+        Bitmap iconBitmap = null;
+        try {
+            // Load the unbadged application icon and pass it to the widget to appear on
+            // the masked view.
+            final String providerPackage = provider.info.provider.getPackageName();
+            Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
+                    UserHandle.of(provider.getUserId()));
+            PackageManager pm = userContext.getPackageManager();
+            Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
+            // Create a bitmap of the icon which is what the widget's remoteview requires.
+            iconBitmap = mIconUtilities.createIconBitmap(icon);
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Fail to get application icon", e);
+            // Provider package removed, no need to mask its views as its state will be
+            // purged very soon.
+            return;
+        }
+
+        final int widgetCount = provider.widgets.size();
+        for (int j = 0; j < widgetCount; j++) {
+            Widget widget = provider.widgets.get(j);
+            if (widget.replaceWithMaskedViewsLocked(mContext, iconBitmap)) {
+                scheduleNotifyUpdateAppWidgetLocked(widget,
+                        widget.getEffectiveViewsLocked());
+            }
+        }
+    }
+
+    private void unmaskWidgetsViewsLocked(Provider provider) {
+        final int widgetCount = provider.widgets.size();
+        for (int j = 0; j < widgetCount; j++) {
+            Widget widget = provider.widgets.get(j);
+            if (widget.clearMaskedViewsLocked()) {
+                scheduleNotifyUpdateAppWidgetLocked(widget,
+                        widget.getEffectiveViewsLocked());
+            }
+        }
+    }
+
     private void resolveHostUidLocked(String pkg, int uid) {
         final int N = mHosts.size();
         for (int i = 0; i < N; i++) {
@@ -3442,6 +3555,9 @@
         PendingIntent broadcast;
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
+        boolean maskedByQuietProfile;
+        boolean maskedBySuspendedPackage;
+
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
 
         public int getUserId() {
@@ -3470,6 +3586,24 @@
         public String toString() {
             return "Provider{" + id + (zombie ? " Z" : "") + '}';
         }
+
+        // returns true if the provider's masked state is changed as a result
+        public boolean setMaskedByQuietProfileLocked(boolean masked) {
+            boolean oldMaskedState = isMaskedLocked();
+            maskedByQuietProfile = masked;
+            return isMaskedLocked() != oldMaskedState;
+        }
+
+        // returns true if the provider's masked state is changed as a result
+        public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
+            boolean oldMaskedState = isMaskedLocked();
+            maskedBySuspendedPackage = masked;
+            return isMaskedLocked() != oldMaskedState;
+        }
+
+        public boolean isMaskedLocked() {
+            return maskedByQuietProfile || maskedBySuspendedPackage;
+        }
     }
 
     private static final class ProviderId {
@@ -3625,28 +3759,24 @@
             return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
         }
 
-        public void replaceWithMaskedViewsLocked(Context context, int iconSize) {
+        private boolean replaceWithMaskedViewsLocked(Context context, Bitmap icon) {
             if (maskedViews != null) {
-                return;
+                return false;
             }
             maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
-            try {
-                Drawable icon = context.getPackageManager().getApplicationIcon(
-                        provider.info.provider.getPackageName());
-                final int width = iconSize;
-                final int height = iconSize;
-                Bitmap iconBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-                Canvas canvas = new Canvas(iconBitmap);
-                icon.setBounds(0, 0, width, height);
-                icon.draw(canvas);
-                maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, iconBitmap);
-            } catch (NameNotFoundException e) {
-                Slog.e(TAG, "Fail to get application icon", e);
+            if (icon != null) {
+                maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, icon);
             }
+            return true;
         }
 
-        public void clearMaskedViewsLocked() {
-            maskedViews = null;
+        private boolean clearMaskedViewsLocked() {
+            if (maskedViews != null) {
+                maskedViews = null;
+                return true;
+            } else {
+                return false;
+            }
         }
 
         public RemoteViews getEffectiveViewsLocked() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 655950e..ba5bb39 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -249,6 +249,7 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
@@ -9344,6 +9345,10 @@
             try {
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                         + " to stackId=" + stackId + " toTop=" + toTop);
+                if (stackId == DOCKED_STACK_ID) {
+                    mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
+                            null /* initialBounds */);
+                }
                 mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS,
                         "moveTaskToStack", ANIMATE);
             } finally {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4879cbfb..914776e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -657,7 +657,6 @@
                     _intent.getCategories().size() == 1 &&
                     _intent.getData() == null &&
                     _intent.getType() == null &&
-                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                     !isResolverActivity()) {
                 // This sure looks like a home activity!
                 mActivityType = HOME_ACTIVITY_TYPE;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 577ca48..0e970b3 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1673,11 +1673,37 @@
             TaskRecord task, ActivityRecord r) {
         if (r.fullscreen) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
-                    + " stackInvisible=" + stackInvisible
-                    + " behindFullscreenActivity=" + behindFullscreenActivity);
+                        + " stackInvisible=" + stackInvisible
+                        + " behindFullscreenActivity=" + behindFullscreenActivity);
             // At this point, nothing else needs to be shown in this task.
             behindFullscreenActivity = true;
-        } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
+        } else if (isHomeStack()) {
+            if (r.isHomeActivity()) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home activity: at " + r
+                        + " stackInvisible=" + stackInvisible
+                        + " behindFullscreenActivity=" + behindFullscreenActivity);
+                // No other activity in the home stack should be visible behind the home activity.
+                // Home activities is usually a translucent activity with the wallpaper behind them.
+                // However, when they don't have the wallpaper behind them, we want to show
+                // activities in the next application stack behind them vs. another activity in the
+                // home stack like recents.
+                behindFullscreenActivity = true;
+            } else if (r.isRecentsActivity()
+                    && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                        "Recents activity returning to app: at " + r
+                        + " stackInvisible=" + stackInvisible
+                        + " behindFullscreenActivity=" + behindFullscreenActivity);
+                // We don't want any other activities in the home stack visible if the recents
+                // activity is going to be returning to an application activity type.
+                // We do this to preserve the visible order the user used to get into the recents
+                // activity. The recents activity is normally translucent and if it doesn't have
+                // the wallpaper behind it the next activity in the home stack shouldn't be visible
+                // when the home stack is brought to the front to display the recents activity from
+                // an app.
+                behindFullscreenActivity = true;
+            }
+        } else if (r.frontOfTask && task.isOverHomeStack()) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
                     + " stackInvisible=" + stackInvisible
                     + " behindFullscreenActivity=" + behindFullscreenActivity);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 31712d9..c41caa8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1549,14 +1549,6 @@
                     mService.mUserController.finishUserSwitch(startingUsers.get(i));
                 }
             }
-            // Complete starting up of background users
-            if (mStartingBackgroundUsers.size() > 0) {
-                startingUsers = new ArrayList<UserState>(mStartingBackgroundUsers);
-                mStartingBackgroundUsers.clear();
-                for (int i = 0; i < startingUsers.size(); i++) {
-                    mService.mUserController.finishUserBoot(startingUsers.get(i));
-                }
-            }
         }
 
         mService.trimApplications();
@@ -2240,8 +2232,9 @@
         }
 
         final ActivityRecord topActivity = task.getTopActivity();
+        final int sourceStackId = task.stack != null ? task.stack.mStackId : INVALID_STACK_ID;
         final boolean mightReplaceWindow =
-                StackId.preserveWindowOnTaskMove(stackId) && topActivity != null;
+                StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) && topActivity != null;
         if (mightReplaceWindow) {
             // We are about to relaunch the activity because its configuration changed due to
             // being maximized, i.e. size change. The activity will first remove the old window
@@ -2263,15 +2256,19 @@
         }
 
         boolean kept = true;
+
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
         } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
                 && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
             kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
-                    RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+                    RESIZE_MODE_SYSTEM, !mightReplaceWindow);
         } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
-            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
         }
 
         if (mightReplaceWindow) {
@@ -2283,7 +2280,7 @@
 
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
-        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);
         resumeFocusedStackTopActivityLocked();
 
         showNonResizeableDockToastIfNeeded(task, preferredLaunchStackId, stackId);
@@ -2765,15 +2762,6 @@
         return homeInFront;
     }
 
-    /**
-     * Add background users to send boot completed events to.
-     * @param userId The user being started in the background
-     * @param uss The state object for the user.
-     */
-    public void startBackgroundUserLocked(int userId, UserState uss) {
-        mStartingBackgroundUsers.add(uss);
-    }
-
     /** Checks whether the userid is a profile of the current user. */
     boolean isCurrentProfileLocked(int userId) {
         if (userId == mCurrentUser) return true;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b8d94eb..98eebea 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -48,6 +48,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.ANIMATE;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
@@ -941,12 +942,8 @@
                 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
-            if (!mMovedHome
-                    && (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                // Caller wants to appear on home activity, so before starting
-                // their own activity we will bring home to the front.
-                mStartActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            if (!mMovedHome) {
+                updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
             }
         } else if (mSourceRecord != null) {
             if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
@@ -1287,11 +1284,7 @@
                             mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
                     mMovedToFront = true;
                 }
-                if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                    // Caller wants to appear on home activity.
-                    intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                }
+                updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
                 mOptions = null;
             }
         }
@@ -1308,6 +1301,23 @@
         return intentActivity;
     }
 
+    private void updateTaskReturnToType(
+            TaskRecord task, int launchFlags, ActivityStack focusedStack) {
+        if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+            // Caller wants to appear on home activity.
+            task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            return;
+        } else if (focusedStack == null || focusedStack.mStackId == HOME_STACK_ID) {
+            // Task will be launched over the home stack, so return home.
+            task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            return;
+        }
+
+        // Else we are coming from an application stack so return to an application.
+        task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+    }
+
     private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
         if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 272f26f..f39ab2f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -128,8 +128,6 @@
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
-    static final boolean IGNORE_RETURN_TO_RECENTS = true;
-
     static final int INVALID_TASK_ID = -1;
 
     final int taskId;       // Unique identifier for this task.
@@ -459,8 +457,8 @@
     }
 
     void setTaskToReturnTo(int taskToReturnTo) {
-        mTaskToReturnTo = (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE)
-            ? HOME_ACTIVITY_TYPE : taskToReturnTo;
+        mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
+                ? HOME_ACTIVITY_TYPE : taskToReturnTo;
     }
 
     int getTaskToReturnTo() {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a21570ce..551f332 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -202,11 +202,11 @@
         }
     }
 
-    void finishUserBoot(UserState uss) {
+    private void finishUserBoot(UserState uss) {
         finishUserBoot(uss, null);
     }
 
-    void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
+    private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
         final int userId = uss.mHandle.getIdentifier();
         synchronized (mService) {
             // Bail if we ended up with a stale user
@@ -711,7 +711,7 @@
                         moveUserToForegroundLocked(uss, oldUserId, userId);
                     }
                 } else {
-                    mService.mStackSupervisor.startBackgroundUserLocked(userId, uss);
+                    mService.mUserController.finishUserBoot(uss);
                 }
 
                 if (needStart) {
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index 07903e9..c1a7ac6 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -107,11 +107,6 @@
     }
 
     @Override
-    public void onRequestConditions(int relevance) {
-        // by convention
-    }
-
-    @Override
     public void onSubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
         mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index a4d5bce..ab3cb83 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -134,12 +134,6 @@
     }
 
     @Override
-    public void onRequestConditions(int relevance) {
-        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
-        // does not advertise conditions
-    }
-
-    @Override
     public void onSubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
         if (!ZenModeConfig.isValidEventConditionId(conditionId)) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8790415..ebdb1b2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2840,17 +2840,20 @@
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
             int[] visibilities = new int[N];
+            int [] importances = new int[N];
             for (int i = 0; i < N; i++) {
                 final NotificationRecord r = mNotificationList.get(i);
                 orderBefore.add(r.getKey());
                 visibilities[i] = r.getPackageVisibilityOverride();
+                importances[i] = r.getImportance();
                 mRankingHelper.extractSignals(r);
             }
             mRankingHelper.sort(mNotificationList);
             for (int i = 0; i < N; i++) {
                 final NotificationRecord r = mNotificationList.get(i);
                 if (!orderBefore.get(i).equals(r.getKey())
-                        || visibilities[i] != r.getPackageVisibilityOverride()) {
+                        || visibilities[i] != r.getPackageVisibilityOverride()
+                        || importances[i] != r.getImportance()) {
                     scheduleSendRankingUpdate();
                     return;
                 }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 44448cc..c9b0ebb 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -107,12 +107,6 @@
     }
 
     @Override
-    public void onRequestConditions(int relevance) {
-        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
-        // does not advertise conditions
-    }
-
-    @Override
     public void onSubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
         if (!ZenModeConfig.isValidScheduleConditionId(conditionId)) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 87f505d..f11872e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -93,7 +93,8 @@
             UserManager.DISALLOW_CAMERA,
             UserManager.DISALLOW_RUN_IN_BACKGROUND,
             UserManager.DISALLOW_DATA_ROAMING,
-            UserManager.DISALLOW_SET_USER_ICON
+            UserManager.DISALLOW_SET_USER_ICON,
+            UserManager.DISALLOW_SET_WALLPAPER
     );
 
     /**
diff --git a/services/core/java/com/android/server/policy/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
index 4658344..b196dec 100644
--- a/services/core/java/com/android/server/policy/IconUtilities.java
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -37,7 +37,7 @@
 /**
  * Various utilities shared amongst the Launcher's classes.
  */
-final class IconUtilities {
+public final class IconUtilities {
     private static final String TAG = "IconUtilities";
 
     private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
@@ -102,7 +102,7 @@
      * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
      * of two sized ARGB_8888 bitmap that can be used as a gl texture.
      */
-    private Bitmap createIconBitmap(Drawable icon) {
+    public Bitmap createIconBitmap(Drawable icon) {
         int width = mIconWidth;
         int height = mIconHeight;
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c7d7096..09c53ae 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -27,6 +27,7 @@
 import android.app.PendingIntent;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
+import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.BroadcastReceiver;
@@ -84,6 +85,7 @@
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.List;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -611,7 +613,7 @@
             return changed;
         }
     }
-    
+
     public WallpaperManagerService(Context context) {
         if (DEBUG) Slog.v(TAG, "WallpaperService startup");
         mContext = context;
@@ -626,7 +628,7 @@
         getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
         loadSettingsLocked(UserHandle.USER_SYSTEM);
     }
-    
+
     private static File getWallpaperDir(int userId) {
         return Environment.getUserSystemDirectory(userId);
     }
@@ -764,7 +766,7 @@
     public void clearWallpaper(String callingPackage) {
         if (DEBUG) Slog.v(TAG, "clearWallpaper");
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
-        if (!isWallpaperSupported(callingPackage)) {
+        if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
             return;
         }
         synchronized (mLock) {
@@ -1000,7 +1002,7 @@
             return null;
         }
 
-        if (!isWallpaperSupported(callingPackage)) {
+        if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
             return null;
         }
 
@@ -1069,7 +1071,7 @@
     }
 
     public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
-        if (isWallpaperSupported(callingPackage)) {
+        if (isWallpaperSupported(callingPackage) && isWallpaperSettingAllowed(callingPackage)) {
             setWallpaperComponent(name);
         }
     }
@@ -1093,7 +1095,7 @@
             }
         }
     }
-    
+
     boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
             boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
@@ -1113,7 +1115,7 @@
                 }
             }
         }
-        
+
         try {
             if (componentName == null) {
                 componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
@@ -1143,9 +1145,9 @@
                 Slog.w(TAG, msg);
                 return false;
             }
-            
+
             WallpaperInfo wi = null;
-            
+
             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
             if (componentName != null && !componentName.equals(mImageWallpaper)) {
                 // Make sure the selected service is actually a wallpaper service.
@@ -1185,7 +1187,7 @@
                     return false;
                 }
             }
-            
+
             // Bind the service!
             if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
             WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
@@ -1314,6 +1316,23 @@
                 callingPackage) == AppOpsManager.MODE_ALLOWED;
     }
 
+    @Override
+    public boolean isWallpaperSettingAllowed(String callingPackage) {
+        final PackageManager pm = mContext.getPackageManager();
+        String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
+        boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
+        if (!uidMatchPackage) {
+            return false;   // callingPackage was faked.
+        }
+
+        final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+        if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
+            return true;
+        }
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1465,7 +1484,7 @@
                                         .getPackageName())) {
                             wallpaper.nextWallpaperComponent = mImageWallpaper;
                         }
-                          
+
                         if (DEBUG) {
                             Slog.v(TAG, "mWidth:" + wallpaper.width);
                             Slog.v(TAG, "mHeight:" + wallpaper.height);
@@ -1666,7 +1685,7 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
-            
+
             pw.println("Permission Denial: can't dump wallpaper service from from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 43a17c9..1821487 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -483,6 +483,62 @@
      * and inner rectangles.
      */
     private static float computePivot(int startPos, float finalScale) {
+
+        /*
+        Theorem of intercepting lines:
+
+          +      +   +-----------------------------------------------+
+          |      |   |                                               |
+          |      |   |                                               |
+          |      |   |                                               |
+          |      |   |                                               |
+        x |    y |   |                                               |
+          |      |   |                                               |
+          |      |   |                                               |
+          |      |   |                                               |
+          |      |   |                                               |
+          |      +   |             +--------------------+            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             |                    |            |
+          |          |             +--------------------+            |
+          |          |                                               |
+          |          |                                               |
+          |          |                                               |
+          |          |                                               |
+          |          |                                               |
+          |          |                                               |
+          |          |                                               |
+          |          +-----------------------------------------------+
+          |
+          |
+          |
+          |
+          |
+          |
+          |
+          |
+          |
+          +                                 ++
+                                         p  ++
+
+        scale = (x - y) / x
+        <=> x = -y / (scale - 1)
+        */
         final float denom = finalScale-1;
         if (Math.abs(denom) < .0001f) {
             return startPos;
@@ -733,14 +789,14 @@
         float unscaledHeight = thumbHeight * scaleW;
         getNextAppTransitionStartRect(taskId, mTmpRect);
         final float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
-        final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
+        final float toY = appRect.top + -unscaledStartY;
         if (mNextAppTransitionScaleUp) {
             // Animation up from the thumbnail to the full screen
             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
                     mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
             scale.setInterpolator(mTouchResponseInterpolator);
             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
-            Animation alpha = new AlphaAnimation(1, 0);
+            Animation alpha = new AlphaAnimation(1f, 0f);
             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
             final float toX = appRect.left + appRect.width() / 2 -
@@ -809,35 +865,27 @@
                             containingFrame, surfaceInsets, taskId);
                 } else {
                     mTmpFromClipRect.set(containingFrame);
-                    // exclude top screen decor (status bar) region from the source clip.
-                    mTmpFromClipRect.top = contentInsets.top;
-                    // App window scaling up to become full screen
                     mTmpToClipRect.set(containingFrame);
-                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-                        // In portrait, we scale the width and clip to the top/left square
-                        scale = thumbWidth / appWidth;
-                        scaledTopDecor = (int) (scale * contentInsets.top);
-                        int unscaledThumbHeight = (int) (thumbHeight / scale);
-                        mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
-                    } else {
-                        // In landscape, we scale the height and clip to the top/left square. We
-                        // only scale the part that is not covered by status bar and the nav bar.
-                        scale = thumbHeight / (appHeight - contentInsets.top
-                                - contentInsets.bottom);
-                        scaledTopDecor = (int) (scale * contentInsets.top);
-                        int unscaledThumbWidth = (int) (thumbWidth / scale);
-                        mTmpFromClipRect.right = mTmpFromClipRect.left + unscaledThumbWidth;
-                        // This removes the navigation bar from the first frame, so it better
-                        // matches the thumbnail. We need to do this explicitly in landscape,
-                        // because in portrait we already crop vertically.
-                        mTmpFromClipRect.bottom = mTmpFromClipRect.bottom - contentInsets.bottom;
-                    }
+
+                    // Containing frame is in screen space, but we need the clip rect in the
+                    // app space.
+                    mTmpFromClipRect.offsetTo(0, 0);
+                    mTmpToClipRect.offsetTo(0, 0);
+
+                    // Exclude insets region from the source clip.
+                    mTmpFromClipRect.inset(contentInsets);
+
+                    // We scale the width and clip to the top/left square
+                    scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
+                    scaledTopDecor = (int) (scale * contentInsets.top);
+                    int unscaledThumbHeight = (int) (thumbHeight / scale);
+                    mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
 
                     mNextAppTransitionInsets.set(contentInsets);
 
                     Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
-                            computePivot(mTmpRect.left, scale),
-                            computePivot(mTmpRect.top, scale));
+                            computePivot(mTmpRect.left - containingFrame.left, scale),
+                            computePivot(mTmpRect.top - containingFrame.top, scale));
                     Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                     Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
 
@@ -879,32 +927,26 @@
                 } else {
                     mTmpFromClipRect.set(containingFrame);
                     mTmpToClipRect.set(containingFrame);
-                    // exclude top screen decor (status bar) region from the destination clip.
-                    mTmpToClipRect.top = contentInsets.top;
-                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-                        // In portrait, we scale the width and clip to the top/left square
-                        scale = thumbWidth / appWidth;
-                        scaledTopDecor = (int) (scale * contentInsets.top);
-                        int unscaledThumbHeight = (int) (thumbHeight / scale);
-                        mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
-                    } else {
-                        // In landscape, we scale the height and clip to the top/left square. We only
-                        // scale the part that is not covered by status bar and the nav bar.
-                        scale = thumbHeight / (appHeight - contentInsets.top - contentInsets.bottom);
-                        scaledTopDecor = (int) (scale * contentInsets.top);
-                        int unscaledThumbWidth = (int) (thumbWidth / scale);
-                        mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
-                        // This removes the navigation bar from the last frame, so it better matches the
-                        // thumbnail. We need to do this explicitly in landscape, because in portrait we
-                        // already crop vertically.
-                        mTmpToClipRect.bottom = mTmpToClipRect.bottom - contentInsets.bottom;
-                    }
+
+                    // Containing frame is in screen space, but we need the clip rect in the
+                    // app space.
+                    mTmpFromClipRect.offsetTo(0, 0);
+                    mTmpToClipRect.offsetTo(0, 0);
+
+                    // Exclude insets region from the target clip.
+                    mTmpToClipRect.inset(contentInsets);
+
+                    // We scale the width and clip to the top/left square
+                    scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
+                    scaledTopDecor = (int) (scale * contentInsets.top);
+                    int unscaledThumbHeight = (int) (thumbHeight / scale);
+                    mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
 
                     mNextAppTransitionInsets.set(contentInsets);
 
                     Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
-                            computePivot(mTmpRect.left, scale),
-                            computePivot(mTmpRect.top, scale));
+                            computePivot(mTmpRect.left - containingFrame.left, scale),
+                            computePivot(mTmpRect.top - containingFrame.top, scale));
                     Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                     Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c542ff6..be1b85c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e7aba6d..47bdb5c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2980,9 +2980,7 @@
             final Rect frame = new Rect(0, 0, width, height);
             final Rect insets = new Rect();
             Rect surfaceInsets = null;
-            final boolean fullscreen = win != null && win.isFrameFullscreen(displayInfo);
             final boolean freeform = win != null && win.inFreeformWorkspace();
-            final boolean docked = win != null && win.inDockedWorkspace();
             if (win != null) {
                 // Containing frame will usually cover the whole screen, including dialog windows.
                 // For freeform workspace windows it will not cover the whole screen and it also
@@ -2994,12 +2992,7 @@
                     frame.set(win.mContainingFrame);
                 }
                 surfaceInsets = win.getAttrs().surfaceInsets;
-                if (fullscreen || docked) {
-                    // For fullscreen windows use the window frames and insets to set the thumbnail
-                    // clip. For non-fullscreen windows we use the app display region so the clip
-                    // isn't affected by the window insets.
-                    insets.set(win.mContentInsets);
-                }
+                insets.set(win.mContentInsets);
             }
 
             if (atoken.mLaunchTaskBehind) {
@@ -3013,7 +3006,7 @@
                     + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
             Animation a = mAppTransition.loadAnimation(lp, transit, enter,
                     mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction,
-                    !fullscreen, atoken.mTask.mTaskId);
+                    freeform, atoken.mTask.mTaskId);
             if (a != null) {
                 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
                 final int containingWidth = frame.width();
@@ -10389,6 +10382,14 @@
         }
     }
 
+    @Override
+    public void getStableInsets(Rect outInsets) throws RemoteException {
+        synchronized (mWindowMap) {
+            final DisplayInfo di = getDefaultDisplayInfoLocked();
+            mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
+        }
+    }
+
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4a9b356..465c7e0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -121,6 +121,8 @@
     static final int DRAG_RESIZE_MODE_FREEFORM = 0;
     static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
 
+    static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
+
     final WindowManagerService mService;
     final WindowManagerPolicy mPolicy;
     final Context mContext;
@@ -1798,10 +1800,6 @@
             return false;
         }
 
-        if (isChildWindow()) {
-            return false;
-        }
-
         Task task = getTask();
         if (task == null || task.inHomeStack()) {
             // Don't save surfaces for home stack apps. These usually resume and draw
@@ -1815,6 +1813,10 @@
             return false;
         }
 
+        if (DEBUG_DISABLE_SAVING_SURFACES) {
+            return false;
+        }
+
         return mAppToken.shouldSaveSurface();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e904ad5..1dbca96 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1225,10 +1225,11 @@
         calculateSurfaceBounds(w, w.getAttrs());
 
         mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, recoveringMemory);
+
+        mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale, mDtDx * w.mVScale,
+                mDsDy * w.mHScale, mDtDy * w.mVScale, recoveringMemory);
         mSurfaceResized = mSurfaceController.setSizeInTransaction(
                 mTmpSize.width(), mTmpSize.height(),
-                mDsDx * w.mHScale, mDtDx * w.mVScale,
-                mDsDy * w.mHScale, mDtDy * w.mVScale,
                 recoveringMemory);
 
         if (mSurfaceResized) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 5674ca2..e14cfdf 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -190,8 +190,27 @@
         }
     }
 
-    boolean setSizeInTransaction(int width, int height, float dsdx, float dtdx, float dsdy, float dtdy,
+    void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
             boolean recoveringMemory) {
+        try {
+            if (SHOW_TRANSACTIONS) logSurface(
+                    "MATRIX [" + dsdx + "," + dtdx + "," + dsdy + "," + dtdy + "]", null);
+            mSurfaceControl.setMatrix(
+                    dsdx, dtdx, dsdy, dtdy);
+        } catch (RuntimeException e) {
+            // If something goes wrong with the surface (such
+            // as running out of memory), don't take down the
+            // entire system.
+            Slog.e(TAG, "Error setting matrix on surface surface" + title
+                    + " MATRIX [" + dsdx + "," + dtdx + "," + dsdy + "," + dtdy + "]", null);
+            if (!recoveringMemory) {
+                mAnimator.reclaimSomeSurfaceMemory("matrix", true);
+            }
+        }
+        return;
+    }
+
+    boolean setSizeInTransaction(int width, int height, boolean recoveringMemory) {
         final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;
         if (surfaceResized) {
             mSurfaceW = width;
@@ -201,8 +220,6 @@
                 if (SHOW_TRANSACTIONS) logSurface(
                         "SIZE " + width + "x" + height, null);
                 mSurfaceControl.setSize(width, height);
-                mSurfaceControl.setMatrix(
-                        dsdx, dtdx, dsdy, dtdy);
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such
                 // as running out of memory), don't take down the
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f2b36820..4022ac6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1459,6 +1459,10 @@
         void settingsGlobalPutString(String name, String value) {
             Settings.Global.putString(mContext.getContentResolver(), name, value);
         }
+
+        void securityLogSetLoggingEnabledProperty(boolean enabled) {
+            SecurityLog.setLoggingEnabledProperty(enabled);
+        }
     }
 
     /**
@@ -8315,7 +8319,7 @@
 
     private void disableDeviceLoggingIfNotCompliant() {
         if (!isDeviceOwnerManagedSingleUserDevice()) {
-            SecurityLog.setLoggingEnabledProperty(false);
+            mInjector.securityLogSetLoggingEnabledProperty(false);
             Slog.w(LOG_TAG, "Device logging turned off as it's no longer a single user device.");
         }
     }
@@ -8326,7 +8330,7 @@
         ensureDeviceOwnerManagingSingleUser(admin);
 
         synchronized (this) {
-            SecurityLog.setLoggingEnabledProperty(enabled);
+            mInjector.securityLogSetLoggingEnabledProperty(enabled);
             if (enabled) {
                 mSecurityLogMonitor.start();
             } else {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 90e4acf..bd37f4a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -281,5 +281,15 @@
         void settingsGlobalPutString(String name, String value) {
             context.settings.settingsGlobalPutString(name, value);
         }
+
+        @Override
+        int settingsGlobalGetInt(String name, int def) {
+            return context.settings.settingsGlobalGetInt(name, def);
+        }
+
+        @Override
+        void securityLogSetLoggingEnabledProperty(boolean enabled) {
+            context.settings.securityLogSetLoggingEnabledProperty(enabled);
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 56667e5..6518732 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -191,6 +191,13 @@
 
         void settingsGlobalPutString(String name, String value) {
         }
+
+        int settingsGlobalGetInt(String name, int def) {
+            return 0;
+        }
+
+        void securityLogSetLoggingEnabledProperty(boolean enabled) {
+        }
     }
 
     public final Context realTestContext;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 597f915ec..354075e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -298,6 +298,10 @@
         }
     }
 
+    public ModuleProperties getModuleProperties() {
+        return moduleProperties;
+    }
+
     //---- SoundTrigger.StatusListener methods
     @Override
     public void onRecognition(RecognitionEvent event) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index 0a06bfa..7722876 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -44,9 +44,6 @@
     public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
     public static final int STATUS_OK = SoundTrigger.STATUS_OK;
 
-    /** The {@link ModuleProperties} for the system, or null if none exists. */
-    private ModuleProperties moduleProperties;
-
     /**
      * Starts recognition for the given keyphraseId.
      *
@@ -76,9 +73,7 @@
      */
     public abstract void stopAllRecognitions();
 
-    public ModuleProperties getModuleProperties() {
-        return moduleProperties;
-    }
+    public abstract ModuleProperties getModuleProperties();
 
     public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 5e8fe9e..682f4a4 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -23,6 +23,7 @@
 import android.hardware.soundtrigger.SoundTrigger;
 import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
 import android.os.Parcel;
 import android.os.ParcelUuid;
@@ -180,6 +181,11 @@
         }
 
         @Override
+        public ModuleProperties getModuleProperties() {
+            return mSoundTriggerHelper.getModuleProperties();
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             mSoundTriggerHelper.dump(fd, pw, args);
         }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 38eb5ee..2560c31 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -557,4 +557,8 @@
     @Override
     public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
     }
+
+    @Override
+    public void getStableInsets(Rect outInsets) throws RemoteException {
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index a833ebe..4e4fcd0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -380,23 +380,17 @@
             config.orientation = Configuration.ORIENTATION_UNDEFINED;
         }
 
-        try {
-            ScreenRound roundness = hardwareConfig.getScreenRoundness();
-            if (roundness != null) {
-                switch (roundness) {
-                    case ROUND:
-                        config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
-                        break;
-                    case NOTROUND:
-                        config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_NO;
-                }
-            } else {
-                config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
+        ScreenRound roundness = hardwareConfig.getScreenRoundness();
+        if (roundness != null) {
+            switch (roundness) {
+                case ROUND:
+                    config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+                    break;
+                case NOTROUND:
+                    config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_NO;
             }
-        } catch (NoSuchMethodError ignored) {
-            // getScreenRoundness was added in later stages of API 15. So, it's not present on some
-            // preview releases of API 15.
-            // TODO: Remove the try catch around Oct 2015.
+        } else {
+            config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
         }
         String locale = getParams().getLocale();
         if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale);