Merge "Don't use deprecated canvas methods"
diff --git a/Android.mk b/Android.mk
index 4fbe094..ffdb3ea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -102,6 +102,7 @@
 	core/java/android/app/IUserSwitchObserver.aidl \
 	core/java/android/app/IWallpaperManager.aidl \
 	core/java/android/app/IWallpaperManagerCallback.aidl \
+	core/java/android/app/admin/IDeviceAdminService.aidl \
 	core/java/android/app/admin/IDevicePolicyManager.aidl \
 	core/java/android/app/trust/IStrongAuthTracker.aidl \
 	core/java/android/app/trust/ITrustManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index b1a1936..3a40ab7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6232,6 +6232,11 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
+  public class DeviceAdminService extends android.app.Service {
+    ctor public DeviceAdminService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+  }
+
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6398,6 +6403,7 @@
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+    field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -9270,6 +9276,8 @@
     field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
     field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
     field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW";
+    field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+    field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
     field public static final java.lang.String ACTION_DELETE = "android.intent.action.DELETE";
     field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
     field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
@@ -9469,8 +9477,9 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
-    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+    field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
     field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -9829,6 +9838,7 @@
   }
 
   public abstract interface ServiceConnection {
+    method public default void onBindingDead(android.content.ComponentName);
     method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
     method public abstract void onServiceDisconnected(android.content.ComponentName);
   }
@@ -10635,6 +10645,7 @@
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
+    field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
     field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
@@ -12693,7 +12704,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public final class Color {
+  public class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -15972,11 +15983,11 @@
     ctor public UsbRequest();
     method public boolean cancel();
     method public void close();
-    method public boolean enqueue(java.nio.ByteBuffer);
     method public java.lang.Object getClientData();
     method public android.hardware.usb.UsbEndpoint getEndpoint();
     method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint);
     method public deprecated boolean queue(java.nio.ByteBuffer, int);
+    method public boolean queue(java.nio.ByteBuffer);
     method public void setClientData(java.lang.Object);
   }
 
@@ -22989,6 +23000,7 @@
     method public void setProfile(android.media.CamcorderProfile);
     method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
     method public void setVideoEncodingBitRate(int);
+    method public void setVideoEncodingProfileLevel(int, int);
     method public void setVideoFrameRate(int) throws java.lang.IllegalStateException;
     method public void setVideoSize(int, int) throws java.lang.IllegalStateException;
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
@@ -24531,19 +24543,19 @@
   }
 
   public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
-    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
+    field public static final int ASPECT_RATIO_1_1 = 2; // 0x2
+    field public static final int ASPECT_RATIO_2_3 = 3; // 0x3
+    field public static final int ASPECT_RATIO_3_2 = 1; // 0x1
+    field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
+    field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
+    field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
     field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
@@ -24561,28 +24573,28 @@
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
     field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
-    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
-    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
-    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
-    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
-    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
-    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
-    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
-    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
-    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
-    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
-    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
+    field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
+    field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
+    field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1
+    field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
+    field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
+    field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
+    field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
+    field public static final int TYPE_ALBUM = 8; // 0x8
+    field public static final int TYPE_ARTIST = 9; // 0x9
+    field public static final int TYPE_CHANNEL = 6; // 0x6
+    field public static final int TYPE_CLIP = 4; // 0x4
+    field public static final int TYPE_EVENT = 5; // 0x5
+    field public static final int TYPE_MOVIE = 0; // 0x0
+    field public static final int TYPE_PLAYLIST = 10; // 0xa
+    field public static final int TYPE_STATION = 11; // 0xb
+    field public static final int TYPE_TRACK = 7; // 0x7
+    field public static final int TYPE_TV_EPISODE = 3; // 0x3
+    field public static final int TYPE_TV_SEASON = 2; // 0x2
+    field public static final int TYPE_TV_SERIES = 1; // 0x1
   }
 
   public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
@@ -24761,10 +24773,10 @@
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
-    field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+    field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0
+    field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2
+    field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1
+    field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3
   }
 
   public final class TvInputInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 0d1c907..956acef 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6436,6 +6436,11 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
+  public class DeviceAdminService extends android.app.Service {
+    ctor public DeviceAdminService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+  }
+
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6623,6 +6628,7 @@
     field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+    field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -9782,6 +9788,8 @@
     field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
     field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
     field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW";
+    field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+    field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
     field public static final java.lang.String ACTION_DELETE = "android.intent.action.DELETE";
     field public static final deprecated java.lang.String ACTION_DEVICE_INITIALIZATION_WIZARD = "android.intent.action.DEVICE_INITIALIZATION_WIZARD";
     field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
@@ -10003,8 +10011,9 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
-    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+    field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
     field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -10365,6 +10374,7 @@
   }
 
   public abstract interface ServiceConnection {
+    method public default void onBindingDead(android.content.ComponentName);
     method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
     method public abstract void onServiceDisconnected(android.content.ComponentName);
   }
@@ -11291,6 +11301,7 @@
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
+    field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
     field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
@@ -13428,7 +13439,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public final class Color {
+  public class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -17435,11 +17446,11 @@
     ctor public UsbRequest();
     method public boolean cancel();
     method public void close();
-    method public boolean enqueue(java.nio.ByteBuffer);
     method public java.lang.Object getClientData();
     method public android.hardware.usb.UsbEndpoint getEndpoint();
     method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint);
     method public deprecated boolean queue(java.nio.ByteBuffer, int);
+    method public boolean queue(java.nio.ByteBuffer);
     method public void setClientData(java.lang.Object);
   }
 
@@ -22834,6 +22845,7 @@
     method public void adjustStreamVolume(int, int, int);
     method public void adjustSuggestedStreamVolume(int, int, int);
     method public void adjustVolume(int, int);
+    method public int dispatchAudioFocusChange(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
     method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
@@ -24785,6 +24797,7 @@
     method public void setProfile(android.media.CamcorderProfile);
     method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
     method public void setVideoEncodingBitRate(int);
+    method public void setVideoEncodingProfileLevel(int, int);
     method public void setVideoFrameRate(int) throws java.lang.IllegalStateException;
     method public void setVideoSize(int, int) throws java.lang.IllegalStateException;
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
@@ -25835,8 +25848,10 @@
 
   public static abstract class AudioPolicy.AudioPolicyFocusListener {
     ctor public AudioPolicy.AudioPolicyFocusListener();
+    method public void onAudioFocusAbandon(android.media.AudioFocusInfo);
     method public void onAudioFocusGrant(android.media.AudioFocusInfo, int);
     method public void onAudioFocusLoss(android.media.AudioFocusInfo, boolean);
+    method public void onAudioFocusRequest(android.media.AudioFocusInfo, int);
   }
 
   public static abstract class AudioPolicy.AudioPolicyStatusListener {
@@ -25851,6 +25866,7 @@
     method public android.media.audiopolicy.AudioPolicy build();
     method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener);
     method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener);
+    method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean);
     method public android.media.audiopolicy.AudioPolicy.Builder setLooper(android.os.Looper) throws java.lang.IllegalArgumentException;
   }
 
@@ -26475,19 +26491,19 @@
   }
 
   public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
-    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
+    field public static final int ASPECT_RATIO_1_1 = 2; // 0x2
+    field public static final int ASPECT_RATIO_2_3 = 3; // 0x3
+    field public static final int ASPECT_RATIO_3_2 = 1; // 0x1
+    field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
+    field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
+    field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
     field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
@@ -26505,28 +26521,28 @@
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
     field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
-    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
-    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
-    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
-    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
-    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
-    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
-    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
-    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
-    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
-    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
-    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
+    field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
+    field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
+    field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1
+    field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
+    field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
+    field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
+    field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
+    field public static final int TYPE_ALBUM = 8; // 0x8
+    field public static final int TYPE_ARTIST = 9; // 0x9
+    field public static final int TYPE_CHANNEL = 6; // 0x6
+    field public static final int TYPE_CLIP = 4; // 0x4
+    field public static final int TYPE_EVENT = 5; // 0x5
+    field public static final int TYPE_MOVIE = 0; // 0x0
+    field public static final int TYPE_PLAYLIST = 10; // 0xa
+    field public static final int TYPE_STATION = 11; // 0xb
+    field public static final int TYPE_TRACK = 7; // 0x7
+    field public static final int TYPE_TV_EPISODE = 3; // 0x3
+    field public static final int TYPE_TV_SEASON = 2; // 0x2
+    field public static final int TYPE_TV_SERIES = 1; // 0x1
   }
 
   public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
@@ -26706,10 +26722,10 @@
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
-    field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+    field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0
+    field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2
+    field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1
+    field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3
   }
 
   public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
diff --git a/api/test-current.txt b/api/test-current.txt
index 7aedea0..c0dcbb4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6251,6 +6251,11 @@
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
+  public class DeviceAdminService extends android.app.Service {
+    ctor public DeviceAdminService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+  }
+
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6426,6 +6431,7 @@
     field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+    field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -9303,6 +9309,8 @@
     field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
     field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
     field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW";
+    field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+    field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
     field public static final java.lang.String ACTION_DELETE = "android.intent.action.DELETE";
     field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
     field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
@@ -9502,8 +9510,9 @@
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
-    field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+    field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
     field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -9862,6 +9871,7 @@
   }
 
   public abstract interface ServiceConnection {
+    method public default void onBindingDead(android.content.ComponentName);
     method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
     method public abstract void onServiceDisconnected(android.content.ComponentName);
   }
@@ -10674,6 +10684,7 @@
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
+    field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
     field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
@@ -12743,7 +12754,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public final class Color {
+  public class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -16027,11 +16038,11 @@
     ctor public UsbRequest();
     method public boolean cancel();
     method public void close();
-    method public boolean enqueue(java.nio.ByteBuffer);
     method public java.lang.Object getClientData();
     method public android.hardware.usb.UsbEndpoint getEndpoint();
     method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint);
     method public deprecated boolean queue(java.nio.ByteBuffer, int);
+    method public boolean queue(java.nio.ByteBuffer);
     method public void setClientData(java.lang.Object);
   }
 
@@ -23102,6 +23113,7 @@
     method public void setProfile(android.media.CamcorderProfile);
     method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
     method public void setVideoEncodingBitRate(int);
+    method public void setVideoEncodingProfileLevel(int, int);
     method public void setVideoFrameRate(int) throws java.lang.IllegalStateException;
     method public void setVideoSize(int, int) throws java.lang.IllegalStateException;
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
@@ -24644,19 +24656,19 @@
   }
 
   public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
-    field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-    field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-    field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-    field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-    field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-    field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-    field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
+    field public static final int ASPECT_RATIO_1_1 = 2; // 0x2
+    field public static final int ASPECT_RATIO_2_3 = 3; // 0x3
+    field public static final int ASPECT_RATIO_3_2 = 1; // 0x1
+    field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
+    field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
+    field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
     field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
@@ -24674,28 +24686,28 @@
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
     field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-    field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-    field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-    field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-    field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-    field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
-    field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-    field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-    field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
-    field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
-    field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
-    field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
-    field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
-    field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
-    field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
-    field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
-    field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
-    field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
-    field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-    field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+    field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
+    field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
+    field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
+    field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1
+    field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
+    field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
+    field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
+    field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
+    field public static final int TYPE_ALBUM = 8; // 0x8
+    field public static final int TYPE_ARTIST = 9; // 0x9
+    field public static final int TYPE_CHANNEL = 6; // 0x6
+    field public static final int TYPE_CLIP = 4; // 0x4
+    field public static final int TYPE_EVENT = 5; // 0x5
+    field public static final int TYPE_MOVIE = 0; // 0x0
+    field public static final int TYPE_PLAYLIST = 10; // 0xa
+    field public static final int TYPE_STATION = 11; // 0xb
+    field public static final int TYPE_TRACK = 7; // 0x7
+    field public static final int TYPE_TV_EPISODE = 3; // 0x3
+    field public static final int TYPE_TV_SEASON = 2; // 0x2
+    field public static final int TYPE_TV_SERIES = 1; // 0x1
   }
 
   public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
@@ -24874,10 +24886,10 @@
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
-    field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
-    field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+    field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0
+    field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2
+    field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1
+    field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3
   }
 
   public final class TvInputInfo implements android.os.Parcelable {
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 3a92b9e..0e2c13e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -26,7 +26,8 @@
     libGLESv1_CM \
     libgui \
     libOpenSLES \
-    libtinyalsa
+    libtinyalsa \
+    libbase
 
 LOCAL_MODULE:= bootanimation
 
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a6d2986..2435ffa 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -38,6 +38,8 @@
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 
+#include <android-base/properties.h>
+
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -67,6 +69,9 @@
 static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
 static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
 static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
+static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
+static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
+
 static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
 static const char SYSTEM_TIME_DIR_NAME[] = "time";
 static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
@@ -106,7 +111,13 @@
     mSession = new SurfaceComposerClient();
 
     // If the system has already booted, the animation is not being used for a boot.
-    mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
+    mSystemBoot = !android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false);
+    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
+    if (powerCtl.empty()) {
+        mShuttingDown = false;
+    } else {
+        mShuttingDown = true;
+    }
 }
 
 void BootAnimation::onFirstRef() {
@@ -314,16 +325,23 @@
     char decrypt[PROPERTY_VALUE_MAX];
     property_get("vold.decrypt", decrypt, "");
 
-    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
+    bool encryptedAnimation = atoi(decrypt) != 0 ||
+        !strcmp("trigger_restart_min_framework", decrypt);
 
-    if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
+    if (!mShuttingDown && encryptedAnimation &&
+        (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
         mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
+        return NO_ERROR;
     }
-    else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
-        mZipFileName = OEM_BOOTANIMATION_FILE;
-    }
-    else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
-        mZipFileName = SYSTEM_BOOTANIMATION_FILE;
+    static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
+    static const char* shutdownFiles[] =
+        {OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
+
+    for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
+        if (access(f, R_OK) == 0) {
+            mZipFileName = f;
+            return NO_ERROR;
+        }
     }
     return NO_ERROR;
 }
@@ -1047,7 +1065,9 @@
     if (!mSystemBoot) {
         return false;
     }
-
+    if (mShuttingDown) { // no audio while shutting down
+        return false;
+    }
     // Read the system property to see if we should play the sound.
     // If it's not present, default to allowed.
     if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
@@ -1073,7 +1093,7 @@
     if (mTimeIsAccurate) {
         return true;
     }
-
+    if (mShuttingDown) return true;
     struct stat statResult;
 
     if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) {
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f1fc98e..181ef1c 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -163,6 +163,7 @@
     bool        mTimeIsAccurate;
     bool        mTimeFormat12Hour;
     bool        mSystemBoot;
+    bool        mShuttingDown;
     String8     mZipFileName;
     SortedVector<String8> mLoadedFiles;
     sp<TimeCheckThread> mTimeCheckThread = nullptr;
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 7344ba7..469c964 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -1,7 +1,7 @@
 service bootanim /system/bin/bootanimation
-    class core
+    class core animation
     user graphics
     group graphics audio
     disabled
     oneshot
-    writepid /dev/stune/top-app/tasks
\ No newline at end of file
+    writepid /dev/stune/top-app/tasks
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 5c7a12c..fe496e3 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -431,12 +431,10 @@
 
     // Force all the animations to end when the duration scale is 0.
     private void forceToEnd() {
-        // TODO: Below is commented out to temp work around b/36241584, uncomment this when it's
-        // fixed.
-//        if (mEndCanBeCalled) {
-//            end();
-//            return;
-//        }
+        if (mEndCanBeCalled) {
+            end();
+            return;
+        }
 
         // Note: we don't want to combine this case with the end() method below because in
         // the case of developer calling end(), we still need to make sure end() is explicitly
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index dbf81f9..d432160 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4159,14 +4159,25 @@
                 mTaskDescription.setPrimaryColor(colorPrimary);
             }
         }
-        // For dev-preview only.
-        if (mTaskDescription.getBackgroundColor() == 0) {
-            int colorBackground = a.getColor(
-                    com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
-            if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
-                mTaskDescription.setBackgroundColor(colorBackground);
-            }
+
+        int colorBackground = a.getColor(
+                com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
+        if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
+            mTaskDescription.setBackgroundColor(colorBackground);
         }
+
+        final int statusBarColor = a.getColor(
+                com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0);
+        if (statusBarColor != 0) {
+            mTaskDescription.setStatusBarColor(statusBarColor);
+        }
+
+        final int navigationBarColor = a.getColor(
+                com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0);
+        if (navigationBarColor != 0) {
+            mTaskDescription.setNavigationBarColor(navigationBarColor);
+        }
+
         a.recycle();
         setTaskDescription(mTaskDescription);
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4004bd6..aede1bb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1145,6 +1145,8 @@
         private String mIconFilename;
         private int mColorPrimary;
         private int mColorBackground;
+        private int mStatusBarColor;
+        private int mNavigationBarColor;
 
         /**
          * Creates the TaskDescription to the specified values.
@@ -1155,7 +1157,7 @@
          *                     opaque.
          */
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
-            this(label, icon, null, colorPrimary, 0);
+            this(label, icon, null, colorPrimary, 0, 0, 0);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
@@ -1168,7 +1170,7 @@
          * @param icon An icon that represents the current state of this activity.
          */
         public TaskDescription(String label, Bitmap icon) {
-            this(label, icon, null, 0, 0);
+            this(label, icon, null, 0, 0, 0, 0);
         }
 
         /**
@@ -1177,24 +1179,26 @@
          * @param label A label and description of the current state of this activity.
          */
         public TaskDescription(String label) {
-            this(label, null, null, 0, 0);
+            this(label, null, null, 0, 0, 0, 0);
         }
 
         /**
          * Creates an empty TaskDescription.
          */
         public TaskDescription() {
-            this(null, null, null, 0, 0);
+            this(null, null, null, 0, 0, 0, 0);
         }
 
         /** @hide */
         public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
-                int colorBackground) {
+                int colorBackground, int statusBarColor, int navigationBarColor) {
             mLabel = label;
             mIcon = icon;
             mIconFilename = iconFilename;
             mColorPrimary = colorPrimary;
             mColorBackground = colorBackground;
+            mStatusBarColor = statusBarColor;
+            mNavigationBarColor = navigationBarColor;
         }
 
         /**
@@ -1214,6 +1218,8 @@
             mIconFilename = other.mIconFilename;
             mColorPrimary = other.mColorPrimary;
             mColorBackground = other.mColorBackground;
+            mStatusBarColor = other.mStatusBarColor;
+            mNavigationBarColor = other.mNavigationBarColor;
         }
 
         private TaskDescription(Parcel source) {
@@ -1253,6 +1259,20 @@
         }
 
         /**
+         * @hide
+         */
+        public void setStatusBarColor(int statusBarColor) {
+            mStatusBarColor = statusBarColor;
+        }
+
+        /**
+         * @hide
+         */
+        public void setNavigationBarColor(int navigationBarColor) {
+            mNavigationBarColor = navigationBarColor;
+        }
+
+        /**
          * Sets the icon for this task description.
          * @hide
          */
@@ -1325,6 +1345,20 @@
             return mColorBackground;
         }
 
+        /**
+         * @hide
+         */
+        public int getStatusBarColor() {
+            return mStatusBarColor;
+        }
+
+        /**
+         * @hide
+         */
+        public int getNavigationBarColor() {
+            return mNavigationBarColor;
+        }
+
         /** @hide */
         public void saveToXml(XmlSerializer out) throws IOException {
             if (mLabel != null) {
@@ -1377,6 +1411,8 @@
             }
             dest.writeInt(mColorPrimary);
             dest.writeInt(mColorBackground);
+            dest.writeInt(mStatusBarColor);
+            dest.writeInt(mNavigationBarColor);
             if (mIconFilename == null) {
                 dest.writeInt(0);
             } else {
@@ -1390,6 +1426,8 @@
             mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
             mColorPrimary = source.readInt();
             mColorBackground = source.readInt();
+            mStatusBarColor = source.readInt();
+            mNavigationBarColor = source.readInt();
             mIconFilename = source.readInt() > 0 ? source.readString() : null;
         }
 
@@ -1407,7 +1445,9 @@
         public String toString() {
             return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
                     " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
-                    " colorBackground: " + mColorBackground;
+                    " colorBackground: " + mColorBackground +
+                    " statusBarColor: " + mColorBackground +
+                    " navigationBarColor: " + mNavigationBarColor;
         }
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e49aad2..d1d462c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -221,6 +221,7 @@
     private long mNetworkBlockSeq = INVALID_PROC_STATE_SEQ;
 
     private ContextImpl mSystemContext;
+    private ContextImpl mSystemUiContext;
 
     static volatile IPackageManager sPackageManager;
 
@@ -2190,9 +2191,19 @@
         }
     }
 
+    public ContextImpl getSystemUiContext() {
+        synchronized (this) {
+            if (mSystemUiContext == null) {
+                mSystemUiContext = ContextImpl.createSystemUiContext(this);
+            }
+            return mSystemUiContext;
+        }
+    }
+
     public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
         synchronized (this) {
             getSystemContext().installSystemApplicationInfo(info, classLoader);
+            getSystemUiContext().installSystemApplicationInfo(info, classLoader);
 
             // give ourselves a default profiler
             mProfiler = new Profiler();
@@ -5031,6 +5042,11 @@
             if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
                 systemTheme.rebase();
             }
+
+            final Theme systemUiTheme = getSystemUiContext().getTheme();
+            if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
+                systemUiTheme.rebase();
+            }
         }
 
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
@@ -5086,9 +5102,10 @@
 
         // Trigger a regular Configuration change event, only with a different assetsSeq number
         // so that we actually call through to all components.
+        // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to
+        // store configurations per-process.
         Configuration newConfig = new Configuration();
-        newConfig.unset();
-        newConfig.assetsSeq = mConfiguration.assetsSeq + 1;
+        newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
         handleConfigurationChanged(newConfig, null);
 
         // Schedule all activities to reload
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 461f9cc..a6838f8b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1352,7 +1352,7 @@
     public Resources getResourcesForApplication(@NonNull ApplicationInfo app)
             throws NameNotFoundException {
         if (app.packageName.equals("system")) {
-            return mContext.mMainThread.getSystemContext().getResources();
+            return mContext.mMainThread.getSystemUiContext().getResources();
         }
         final boolean sameUid = (app.uid == Process.myUid());
         final Resources r = mContext.mMainThread.getTopLevelResources(
@@ -1383,7 +1383,7 @@
                     "Call does not support special user #" + userId);
         }
         if ("system".equals(appPackageName)) {
-            return mContext.mMainThread.getSystemContext().getResources();
+            return mContext.mMainThread.getSystemUiContext().getResources();
         }
         try {
             ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, sDefaultFlags, userId);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f95fa99..c5e970f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2217,6 +2217,18 @@
         return context;
     }
 
+    /**
+     * System Context to be used for UI. This Context has resources that can be themed.
+     */
+    static ContextImpl createSystemUiContext(ActivityThread mainThread) {
+        LoadedApk packageInfo = new LoadedApk(mainThread);
+        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
+                null);
+        context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null,
+                packageInfo.getCompatibilityInfo()));
+        return context;
+    }
+
     static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
diff --git a/core/java/android/app/IServiceConnection.aidl b/core/java/android/app/IServiceConnection.aidl
index 6804071..97042aa 100644
--- a/core/java/android/app/IServiceConnection.aidl
+++ b/core/java/android/app/IServiceConnection.aidl
@@ -21,6 +21,6 @@
 
 /** @hide */
 oneway interface IServiceConnection {
-    void connected(in ComponentName name, IBinder service);
+    void connected(in ComponentName name, IBinder service, boolean dead);
 }
 
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index dbed1be..4205db0 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -88,8 +88,8 @@
  * @hide
  */
 public final class LoadedApk {
-
-    private static final String TAG = "LoadedApk";
+    static final String TAG = "LoadedApk";
+    static final boolean DEBUG = false;
 
     private final ActivityThread mActivityThread;
     final String mPackageName;
@@ -641,8 +641,7 @@
         final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
                 TextUtils.join(File.pathSeparator, zipPaths);
 
-        if (ActivityThread.localLOGV)
-            Slog.v(ActivityThread.TAG, "Class path: " + zip +
+        if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip +
                     ", JNI path: " + librarySearchPath);
 
         boolean needToSetupJitProfiles = false;
@@ -1371,12 +1370,14 @@
             LoadedApk.ServiceDispatcher sd = null;
             ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
             if (map != null) {
+                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                 sd = map.get(c);
             }
             if (sd == null) {
                 sd = new ServiceDispatcher(c, context, handler, flags);
+                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                 if (map == null) {
-                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
+                    map = new ArrayMap<>();
                     mServices.put(context, map);
                 }
                 map.put(c, sd);
@@ -1396,6 +1397,7 @@
             if (map != null) {
                 sd = map.get(c);
                 if (sd != null) {
+                    if (DEBUG) Slog.d(TAG, "Removing dispatcher " + sd + " for conn " + c);
                     map.remove(c);
                     sd.doForget();
                     if (map.size() == 0) {
@@ -1461,10 +1463,11 @@
                 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
             }
 
-            public void connected(ComponentName name, IBinder service) throws RemoteException {
+            public void connected(ComponentName name, IBinder service, boolean dead)
+                    throws RemoteException {
                 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                 if (sd != null) {
-                    sd.connected(name, service);
+                    sd.connected(name, service, dead);
                 }
             }
         }
@@ -1533,23 +1536,23 @@
             return mUnbindLocation;
         }
 
-        public void connected(ComponentName name, IBinder service) {
+        public void connected(ComponentName name, IBinder service, boolean dead) {
             if (mActivityThread != null) {
-                mActivityThread.post(new RunConnection(name, service, 0));
+                mActivityThread.post(new RunConnection(name, service, 0, dead));
             } else {
-                doConnected(name, service);
+                doConnected(name, service, dead);
             }
         }
 
         public void death(ComponentName name, IBinder service) {
             if (mActivityThread != null) {
-                mActivityThread.post(new RunConnection(name, service, 1));
+                mActivityThread.post(new RunConnection(name, service, 1, false));
             } else {
                 doDeath(name, service);
             }
         }
 
-        public void doConnected(ComponentName name, IBinder service) {
+        public void doConnected(ComponentName name, IBinder service, boolean dead) {
             ServiceDispatcher.ConnectionInfo old;
             ServiceDispatcher.ConnectionInfo info;
 
@@ -1594,6 +1597,9 @@
             if (old != null) {
                 mConnection.onServiceDisconnected(name);
             }
+            if (dead) {
+                mConnection.onBindingDead(name);
+            }
             // If there is a new service, it is now connected.
             if (service != null) {
                 mConnection.onServiceConnected(name, service);
@@ -1616,15 +1622,16 @@
         }
 
         private final class RunConnection implements Runnable {
-            RunConnection(ComponentName name, IBinder service, int command) {
+            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                 mName = name;
                 mService = service;
                 mCommand = command;
+                mDead = dead;
             }
 
             public void run() {
                 if (mCommand == 0) {
-                    doConnected(mName, mService);
+                    doConnected(mName, mService, mDead);
                 } else if (mCommand == 1) {
                     doDeath(mName, mService);
                 }
@@ -1633,6 +1640,7 @@
             final ComponentName mName;
             final IBinder mService;
             final int mCommand;
+            final boolean mDead;
         }
 
         private final class DeathMonitor implements IBinder.DeathRecipient
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b42df5e..489a0f0 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -984,7 +984,7 @@
                 final ResourcesKey key = mResourceImpls.keyAt(i);
                 final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
                 final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
-                if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) {
+                if (impl != null && (key.mResDir == null || key.mResDir.equals(baseCodePath))) {
                     updatedResourceKeys.put(impl, new ResourcesKey(
                             key.mResDir,
                             key.mSplitResDirs,
diff --git a/core/java/android/app/admin/DeviceAdminService.java b/core/java/android/app/admin/DeviceAdminService.java
new file mode 100644
index 0000000..cd0b1bf
--- /dev/null
+++ b/core/java/android/app/admin/DeviceAdminService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.admin;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Base class for a service that device owner/profile owners can optionally have.
+ *
+ * <p>The system searches for it with an intent filter with the
+ * {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} action, and tries to keep a bound
+ * connection as long as the hosting user is running, so that the device/profile owner is always
+ * considered to be in the foreground.
+ *
+ * <p>Device/profile owners can use
+ * {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)}
+ * to disable/enable its own service.  For example, when a device/profile owner no longer needs
+ * to be in the foreground, it can (and should) disable its service.
+ *
+ * <p>The service must not be exported.
+ *
+ * <p>TODO: Describe how the system handles crashes in DO/PO.
+ */
+public class DeviceAdminService extends Service {
+    private final IDeviceAdminServiceImpl mImpl;
+
+    public DeviceAdminService() {
+        mImpl = new IDeviceAdminServiceImpl();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mImpl.asBinder();
+    }
+
+    private class IDeviceAdminServiceImpl extends IDeviceAdminService.Stub {
+    }
+
+    // So far, we have no methods in this class.
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6d8d5e9..2f0a630 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1515,6 +1515,16 @@
     public @interface ProvisioningPreCondition {}
 
     /**
+     * Service action: Action for a service that device owner and profile owner can optionally
+     * own.  If a device owner or a profile owner has such a service, the system tries to keep
+     * a bound connection to it, in order to keep their process always running.
+     * The service must not be exported.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String ACTION_DEVICE_ADMIN_SERVICE
+            = "android.app.action.DEVICE_ADMIN_SERVICE";
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
diff --git a/core/java/android/app/admin/IDeviceAdminService.aidl b/core/java/android/app/admin/IDeviceAdminService.aidl
new file mode 100644
index 0000000..5276ed5
--- /dev/null
+++ b/core/java/android/app/admin/IDeviceAdminService.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+/**
+ * @hide
+ */
+interface IDeviceAdminService {
+}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index a04a7b2..f8c139f 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -524,7 +524,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
@@ -579,7 +582,10 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                mCloseGuard.warnIfOpen();
+                if (mCloseGuard != null) {
+                    mCloseGuard.warnIfOpen();
+                }
+
                 close();
             } finally {
                 super.finalize();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 98ae132..69cd99c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2942,7 +2942,10 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                mCloseGuard.warnIfOpen();
+                if (mCloseGuard != null) {
+                    mCloseGuard.warnIfOpen();
+                }
+
                 close();
             } finally {
                 super.finalize();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aa2adc7..a585720 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4642,4 +4642,18 @@
     public Handler getMainThreadHandler() {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
+
+    /**
+     * Throws an exception if the Context is using system resources,
+     * which are non-runtime-overlay-themable and may show inconsistent UI.
+     * @hide
+     */
+    public void assertRuntimeOverlayThemable() {
+        // Resources.getSystem() is a singleton and the only Resources not managed by
+        // ResourcesManager; therefore Resources.getSystem() is not themable.
+        if (getResources() == Resources.getSystem()) {
+            throw new IllegalArgumentException("Non-UI context used to display UI; "
+                    + "get a UI context from ActivityThread#getSystemUiContext()");
+        }
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8f44fcd..95c54ed 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,8 +16,6 @@
 
 package android.content;
 
-import static android.content.ContentProvider.maybeAddUserId;
-
 import android.annotation.AnyRes;
 import android.annotation.BroadcastBehavior;
 import android.annotation.IntDef;
@@ -43,6 +41,7 @@
 import android.os.ShellCommand;
 import android.os.StrictMode;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
@@ -50,9 +49,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
-
 import com.android.internal.util.XmlUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -70,6 +67,8 @@
 import java.util.Objects;
 import java.util.Set;
 
+import static android.content.ContentProvider.maybeAddUserId;
+
 /**
  * An intent is an abstract description of an operation to be performed.  It
  * can be used with {@link Context#startActivity(Intent) startActivity} to
@@ -3368,6 +3367,32 @@
             ACTION_DYNAMIC_SENSOR_CHANGED = "android.intent.action.DYNAMIC_SENSOR_CHANGED";
 
     /**
+     * Broadcast Action: The default subscription has changed.  This has the following
+     * extra values:</p>
+     * The {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default subscription index
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default sms subscription has changed.  This has the following
+     * extra values:</p>
+     * {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default sms
+     * subscription index
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and
+     * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription
+     * which has changed.
+     */
+    public static final String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX";
+
+    /**
      * Deprecated - use {@link #ACTION_FACTORY_RESET} instead.
      *
      * {@hide}
@@ -3887,23 +3912,9 @@
     public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
 
     /**
-     * A content: URI holding a stream of data associated with the Intent, used
-     * with {@link #ACTION_SEND} to supply the data being sent.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN} this value
-     * will be automatically promoted to {@link Intent#setClipData(ClipData)}
-     * when that value is not already defined.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#O} this value will be
-     * automatically demoted from {@link Intent#getClipData()} when this value
-     * is not already defined.
-     *
-     * @deprecated apps should use {@link Intent#setClipData(ClipData)} and
-     *             {@link Intent#getClipData()} instead of this extra, since
-     *             only those APIs can extend temporary permission grants to the
-     *             underlying resource.
+     * A content: URI holding a stream of data associated with the Intent,
+     * used with {@link #ACTION_SEND} to supply the data being sent.
      */
-    @Deprecated
     public static final String EXTRA_STREAM = "android.intent.extra.STREAM";
 
     /**
@@ -9448,21 +9459,6 @@
                 mContentUserHint = UserHandle.USER_CURRENT;
             }
         }
-
-        // If someone is sending us ClipData, but not EXTRA_STREAM, offer to
-        // downgrade that content for older apps to find
-        if (mClipData != null && mClipData.getItemCount() > 0 && !hasExtra(EXTRA_STREAM)) {
-            final String action = getAction();
-            if (ACTION_SEND.equals(action)) {
-                putExtra(EXTRA_STREAM, mClipData.getItemAt(0).getUri());
-            } else if (ACTION_SEND_MULTIPLE.equals(action)) {
-                final ArrayList<Uri> list = new ArrayList<>();
-                for (int i = 0; i < mClipData.getItemCount(); i++) {
-                    list.add(mClipData.getItemAt(i).getUri());
-                }
-                putExtra(EXTRA_STREAM, list);
-            }
-        }
     }
 
     /**
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index d115ce4..8e428f9 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -37,7 +37,7 @@
      * @param service The IBinder of the Service's communication channel,
      * which you can now make calls on.
      */
-    public void onServiceConnected(ComponentName name, IBinder service);
+    void onServiceConnected(ComponentName name, IBinder service);
 
     /**
      * Called when a connection to the Service has been lost.  This typically
@@ -49,5 +49,18 @@
      * @param name The concrete component name of the service whose
      * connection has been lost.
      */
-    public void onServiceDisconnected(ComponentName name);
+    void onServiceDisconnected(ComponentName name);
+
+    /**
+     * Called when the binding to this connection is dead.  This means the
+     * interface will never receive another connection.  The application will
+     * need to unbind and rebind the connection to activate it again.  This may
+     * happen, for example, if the application hosting the service it is bound to
+     * has been updated.
+     *
+     * @param name The concrete component name of the service whose
+     * connection is dead.
+     */
+    default void onBindingDead(ComponentName name) {
+    }
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 912ce3d..4d76755 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -419,7 +419,7 @@
      */
     private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
         if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
-            Log.e(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
+            Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
         }
     }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 17cb027..afa34a0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2167,7 +2167,6 @@
      * {@link #hasSystemFeature}: The device supports only leanback UI. Only
      * applications designed for this experience should be run, though this is
      * not enforced by the system.
-     * @hide
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
diff --git a/core/java/android/hardware/SensorDirectChannel.java b/core/java/android/hardware/SensorDirectChannel.java
index a65d57d..2c499b0 100644
--- a/core/java/android/hardware/SensorDirectChannel.java
+++ b/core/java/android/hardware/SensorDirectChannel.java
@@ -152,7 +152,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index b276008..e845359 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -102,6 +102,16 @@
             int displayId, DisplayInfo info);
 
     /**
+     * Get current display info without override from WindowManager.
+     * Current implementation of LogicalDisplay#getDisplayInfoLocked() always returns display info
+     * with overrides from WM if set. This method can be used for getting real display size without
+     * overrides to determine if real changes to display metrics happened.
+     * @param displayId Id of the target display.
+     * @param outInfo {@link DisplayInfo} to fill.
+     */
+    public abstract void getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo);
+
+    /**
      * Called by the window manager to perform traversals while holding a
      * surface flinger transaction.
      */
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index ffd6ec3..1bf2137 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -332,7 +332,9 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
         } finally {
             super.finalize();
         }
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index badb344..3ff71ff 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -60,9 +60,11 @@
     // Prevent the connection from being finalized
     private UsbDeviceConnection mConnection;
 
-    /** Whether this buffer was {@link #enqueue enqueued (new behavior)} or {@link #queue queued
-     * (deprecared behavior)}. */
-    private boolean mIsUsingEnqueue;
+    /**
+     * Whether this buffer was {@link #queue(ByteBuffer) queued using the new behavior} or
+     * {@link #queue(ByteBuffer, int) queued using the deprecated behavior}.
+     */
+    private boolean mIsUsingNewQueue;
 
     /** Temporary buffer than might be used while buffer is enqueued */
     private ByteBuffer mTempBuffer;
@@ -114,7 +116,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
@@ -172,7 +177,7 @@
      *
      * @return true if the queueing operation succeeded
      *
-     * @deprecated Use {@link #enqueue(ByteBuffer)} instead.
+     * @deprecated Use {@link #queue(ByteBuffer)} instead.
      */
     @Deprecated
     public boolean queue(ByteBuffer buffer, int length) {
@@ -219,23 +224,23 @@
      *
      * @return true if the queueing operation succeeded
      */
-    public boolean enqueue(@Nullable ByteBuffer buffer) {
+    public boolean queue(@Nullable ByteBuffer buffer) {
         // Request need to be initialized
         Preconditions.checkState(mNativeContext != 0, "request is not initialized");
 
-        // Request can not be currently enqueued
-        Preconditions.checkState(!mIsUsingEnqueue, "request is currently enqueued");
+        // Request can not be currently queued
+        Preconditions.checkState(!mIsUsingNewQueue, "this request is currently queued");
 
         boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
-        boolean wasEnqueued;
+        boolean wasQueued;
 
         synchronized (mLock) {
             mBuffer = buffer;
 
             if (buffer == null) {
                 // Null buffers enqueue empty USB requests which is supported
-                mIsUsingEnqueue = true;
-                wasEnqueued = native_enqueue(null, 0, 0);
+                mIsUsingNewQueue = true;
+                wasQueued = native_queue(null, 0, 0);
             } else {
                 // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
                 Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
@@ -260,18 +265,18 @@
                     buffer = mTempBuffer;
                 }
 
-                mIsUsingEnqueue = true;
-                wasEnqueued = native_enqueue(buffer, buffer.position(), buffer.remaining());
+                mIsUsingNewQueue = true;
+                wasQueued = native_queue(buffer, buffer.position(), buffer.remaining());
             }
         }
 
-        if (!wasEnqueued) {
-            mIsUsingEnqueue = false;
+        if (!wasQueued) {
+            mIsUsingNewQueue = false;
             mTempBuffer = null;
             mBuffer = null;
         }
 
-        return wasEnqueued;
+        return wasQueued;
     }
 
     /* package */ void dequeue() {
@@ -279,9 +284,9 @@
         int bytesTransferred;
 
         synchronized (mLock) {
-            if (mIsUsingEnqueue) {
+            if (mIsUsingNewQueue) {
                 bytesTransferred = native_dequeue_direct();
-                mIsUsingEnqueue = false;
+                mIsUsingNewQueue = false;
 
                 if (mBuffer == null) {
                     // Nothing to do
@@ -332,7 +337,7 @@
     private native boolean native_init(UsbDeviceConnection connection, int ep_address,
             int ep_attributes, int ep_max_packet_size, int ep_interval);
     private native void native_close();
-    private native boolean native_enqueue(ByteBuffer buffer, int offset, int length);
+    private native boolean native_queue(ByteBuffer buffer, int offset, int length);
     private native boolean native_queue_array(byte[] buffer, int length, boolean out);
     private native int native_dequeue_array(byte[] buffer, int length, boolean out);
     private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out);
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 495340d..63bbd96 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -38,9 +38,6 @@
 
     boolean isUidForeground(int uid);
 
-    /** Higher priority listener before general event dispatch */
-    void setConnectivityListener(INetworkPolicyListener listener);
-
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e2100bd..660d53a 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10324,6 +10324,10 @@
             INSTANT_APP_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
             INSTANT_APP_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
             INSTANT_APP_SETTINGS.add(AIRPLANE_MODE_ON);
+            INSTANT_APP_SETTINGS.add(WINDOW_ANIMATION_SCALE);
+            INSTANT_APP_SETTINGS.add(TRANSITION_ANIMATION_SCALE);
+            INSTANT_APP_SETTINGS.add(ANIMATOR_DURATION_SCALE);
+            INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES);
         }
 
         /**
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 749cf08..b3fe8a8 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -158,7 +158,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             IoUtils.closeQuietly(this);
         } finally {
             super.finalize();
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3316f3a..aac5baa 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -529,6 +529,18 @@
         }
     }
 
+    /**
+     * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
+     * whether callbacks are currently running.
+     * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
+     * @hide
+     */
+    public long getLastFrameTimeNanos() {
+        synchronized (mLock) {
+            return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
+        }
+    }
+
     private void scheduleFrameLocked(long now) {
         if (!mFrameScheduled) {
             mFrameScheduled = true;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5494377..6dedbde 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -50,7 +50,7 @@
  * <li>The real display area specifies the part of the display that contains content
  * including the system decorations.  Even so, the real display area may be smaller than the
  * physical size of the display if the window manager is emulating a smaller display
- * using (adb shell am display-size).  Use the following methods to query the
+ * using (adb shell wm size).  Use the following methods to query the
  * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li>
  * </ul>
  * </p><p>
@@ -947,7 +947,7 @@
      * The size is adjusted based on the current rotation of the display.
      * </p><p>
      * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell am display-size).
+     * window manager is emulating a smaller display (using adb shell wm size).
      * </p>
      *
      * @param outSize Set to the real size of the display.
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index ae1ee42..d25e5f0 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -118,7 +118,7 @@
      * @return the "effective" root of {@param focused}
      */
     private ViewGroup getEffectiveRoot(ViewGroup root, View focused) {
-        if (focused == null) {
+        if (focused == null || focused == root) {
             return root;
         }
         ViewParent effective = focused.getParent();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 884283d..b12a767 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25523,7 +25523,7 @@
      * <p>
      * The tooltip will be displayed:
      * <ul>
-     * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context
+     * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context
      * menu). </li>
      * <li>On hover, after a brief delay since the pointer has stopped moving </li>
      * </ul>
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 79b0420..958d761 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1018,9 +1018,20 @@
         }
     }
 
-    /** @hide */
+    /**
+     * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0
+     * is publicly released because previous implementations of that class had relied on this method
+     * via reflection.
+     *
+     * @deprecated This is a hidden API. You should never use this.
+     * @hide
+     */
+    @Deprecated
     public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
         try {
+            Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed "
+                    + "soon. If you are using android.support.v7.widget.SearchView, please update "
+                    + "to version 26.0 or newer version.");
             mService.showSoftInput(mClient, flags, resultReceiver);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 1abb59b..a70209c 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -74,6 +74,7 @@
     private final Rect mOldStableInsets = new Rect();
     private final Rect mSystemInsets = new Rect();
     private final Rect mStableInsets = new Rect();
+    private final Rect mTmpRect = new Rect();
 
     public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
             Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
@@ -370,12 +371,6 @@
         DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
         mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
         final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
-        final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom,
-                systemInsets.bottom);
-        final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
-                systemInsets.right);
-        final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
-                systemInsets.left);
         if (mStatusBarColor != null) {
             mStatusBarColor.setBounds(0, 0, left + width, topInset);
             mStatusBarColor.draw(canvas);
@@ -385,14 +380,8 @@
         // don't want the navigation bar background be moving around when resizing in docked mode.
         // However, we need it for the transitions into/out of docked mode.
         if (mNavigationBarColor != null && fullscreen) {
-            final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
-            if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
-                mNavigationBarColor.setBounds(width - size, 0, width, height);
-            } else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) {
-                mNavigationBarColor.setBounds(0, 0, size, height);
-            } else {
-                mNavigationBarColor.setBounds(0, height - size, width, height);
-            }
+            DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect);
+            mNavigationBarColor.setBounds(mTmpRect);
             mNavigationBarColor.draw(canvas);
         }
         mSystemBarBackgroundNode.end(canvas);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index a8e16c9..653796d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -119,6 +119,21 @@
     // The height of a window which has not in DIP.
     private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
 
+    public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
+            new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+                    Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
+                    Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+                    com.android.internal.R.id.statusBarBackground,
+                    FLAG_FULLSCREEN);
+
+    public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
+            new ColorViewAttributes(
+                    SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+                    Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
+                    Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+                    com.android.internal.R.id.navigationBarBackground,
+                    0 /* hideWindowFlag */);
+
     // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
     // size calculation takes the shadow size into account. We set the elevation currently
     // to max until the first layout command has been executed.
@@ -162,18 +177,10 @@
     // View added at runtime to draw under the navigation bar area
     private View mNavigationGuard;
 
-    private final ColorViewState mStatusColorViewState = new ColorViewState(
-            SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
-            Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
-            Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
-            com.android.internal.R.id.statusBarBackground,
-            FLAG_FULLSCREEN);
-    private final ColorViewState mNavigationColorViewState = new ColorViewState(
-            SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
-            Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
-            Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
-            com.android.internal.R.id.navigationBarBackground,
-            0 /* hideWindowFlag */);
+    private final ColorViewState mStatusColorViewState =
+            new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
+    private final ColorViewState mNavigationColorViewState =
+            new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);
 
     private final Interpolator mShowInterpolator;
     private final Interpolator mHideInterpolator;
@@ -983,35 +990,50 @@
         return false;
     }
 
-    static int getColorViewTopInset(int stableTop, int systemTop) {
+    public static int getColorViewTopInset(int stableTop, int systemTop) {
         return Math.min(stableTop, systemTop);
     }
 
-    static int getColorViewBottomInset(int stableBottom, int systemBottom) {
+    public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
         return Math.min(stableBottom, systemBottom);
     }
 
-    static int getColorViewRightInset(int stableRight, int systemRight) {
+    public static int getColorViewRightInset(int stableRight, int systemRight) {
         return Math.min(stableRight, systemRight);
     }
 
-    static int getColorViewLeftInset(int stableLeft, int systemLeft) {
+    public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
         return Math.min(stableLeft, systemLeft);
     }
 
-    static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
+    public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
         return bottomInset == 0 && rightInset > 0;
     }
 
-    static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
+    public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
         return bottomInset == 0 && leftInset > 0;
     }
 
-    static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
+    public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
         return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
                 : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
     }
 
+    public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
+            Rect contentInsets, Rect outRect) {
+        final int bottomInset = getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom);
+        final int leftInset = getColorViewLeftInset(stableInsets.left, contentInsets.left);
+        final int rightInset = getColorViewLeftInset(stableInsets.right, contentInsets.right);
+        final int size = getNavBarSize(bottomInset, rightInset, leftInset);
+        if (isNavBarToRightEdge(bottomInset, rightInset)) {
+            outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
+        } else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
+            outRect.set(0, 0, size, canvasHeight);
+        } else {
+            outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
+        }
+    }
+
     WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
@@ -1131,9 +1153,14 @@
     }
 
     private int calculateStatusBarColor() {
-        int flags = mWindow.getAttributes().flags;
-        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? mSemiTransparentStatusBarColor
-                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? mWindow.mStatusBarColor
+        return calculateStatusBarColor(mWindow.getAttributes().flags,
+                mSemiTransparentStatusBarColor, mWindow.mStatusBarColor);
+    }
+
+    public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor,
+            int statusBarColor) {
+        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor
+                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor
                 : Color.BLACK;
     }
 
@@ -1160,13 +1187,9 @@
     private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
             int size, boolean verticalBar, boolean seascape, int sideMargin,
             boolean animate, boolean force) {
-        state.present = (sysUiVis & state.systemUiHideFlag) == 0
-                && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
-                && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
-                        || force);
-        boolean show = state.present
-                && (color & Color.BLACK) != 0
-                && ((mWindow.getAttributes().flags & state.translucentFlag) == 0  || force);
+        state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
+        boolean show = state.attributes.isVisible(state.present, color,
+                mWindow.getAttributes().flags, force);
         boolean showView = show && !isResizing() && size > 0;
 
         boolean visibilityChanged = false;
@@ -1175,15 +1198,15 @@
         int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
         int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
         int resolvedGravity = verticalBar
-                ? (seascape ? state.seascapeGravity : state.horizontalGravity)
-                : state.verticalGravity;
+                ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
+                : state.attributes.verticalGravity;
 
         if (view == null) {
             if (showView) {
                 state.view = view = new View(mContext);
                 view.setBackgroundColor(color);
-                view.setTransitionName(state.transitionName);
-                view.setId(state.id);
+                view.setTransitionName(state.attributes.transitionName);
+                view.setId(state.attributes.id);
                 visibilityChanged = true;
                 view.setVisibility(INVISIBLE);
                 state.targetVisibility = VISIBLE;
@@ -2269,6 +2292,15 @@
         boolean visible;
         int color;
 
+        final ColorViewAttributes attributes;
+
+        ColorViewState(ColorViewAttributes attributes) {
+            this.attributes = attributes;
+        }
+    }
+
+    public static class ColorViewAttributes {
+
         final int id;
         final int systemUiHideFlag;
         final int translucentFlag;
@@ -2278,9 +2310,9 @@
         final String transitionName;
         final int hideWindowFlag;
 
-        ColorViewState(int systemUiHideFlag,
-                int translucentFlag, int verticalGravity, int horizontalGravity,
-                int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
+        private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
+                int horizontalGravity, int seascapeGravity, String transitionName, int id,
+                int hideWindowFlag) {
             this.id = id;
             this.systemUiHideFlag = systemUiHideFlag;
             this.translucentFlag = translucentFlag;
@@ -2290,6 +2322,24 @@
             this.transitionName = transitionName;
             this.hideWindowFlag = hideWindowFlag;
         }
+
+        public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
+            return (sysUiVis & systemUiHideFlag) == 0
+                    && (windowFlags & hideWindowFlag) == 0
+                    && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+                    || force);
+        }
+
+        public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
+            return present
+                    && (color & Color.BLACK) != 0
+                    && ((windowFlags & translucentFlag) == 0  || force);
+        }
+
+        public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
+            final boolean present = isPresent(sysUiVis, windowFlags, force);
+            return isVisible(present, color, windowFlags, force);
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java
new file mode 100644
index 0000000..e40090f
--- /dev/null
+++ b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.view;
+
+import android.os.Handler;
+import android.os.Message;
+import android.view.Choreographer;
+import android.view.Display;
+
+/**
+ * Utility class to schedule things at vsync-sf instead of vsync-app
+ * @hide
+ */
+public class SurfaceFlingerVsyncChoreographer {
+
+    private static final long ONE_MS_IN_NS = 1000000;
+    private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000;
+
+    private final Handler mHandler;
+    private final Choreographer mChoreographer = Choreographer.getInstance();
+
+    /**
+     * The offset between vsync-app and vsync-surfaceflinger. See
+     * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary.
+     */
+    private long mSurfaceFlingerOffsetMs;
+
+    public SurfaceFlingerVsyncChoreographer(Handler handler, Display display) {
+        mHandler = handler;
+        mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display);
+    }
+
+    public long getSurfaceFlingerOffsetMs() {
+        return mSurfaceFlingerOffsetMs;
+    }
+
+    /**
+     * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app
+     * is a couple of milliseconds before vsync-sf, a touch or animation event that causes a surface
+     * flinger transaction are sometimes processed before the vsync-sf tick, and sometimes after,
+     * which leads to jank. Figure out this difference here and then post all the touch/animation
+     * events to start being processed at vsync-sf.
+     *
+     * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf.
+     */
+    private long calculateAppSurfaceFlingerVsyncOffsetMs(Display display) {
+
+        // Calculate vsync offset from SurfaceFlinger.
+        // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs
+        long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate());
+        long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS);
+        return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS);
+    }
+
+    public void scheduleAtSfVsync(Runnable r) {
+        final long delay = calculateDelay();
+        if (delay <= 0) {
+            r.run();
+        } else {
+            mHandler.postDelayed(r, delay);
+        }
+    }
+
+    public void scheduleAtSfVsync(Handler h, Message m) {
+        final long delay = calculateDelay();
+        if (delay <= 0) {
+            h.handleMessage(m);
+        } else {
+            m.setAsynchronous(true);
+            h.sendMessageDelayed(m, delay);
+        }
+    }
+
+    private long calculateDelay() {
+        final long sinceFrameStart = System.nanoTime() - mChoreographer.getLastFrameTimeNanos();
+        return mSurfaceFlingerOffsetMs - sinceFrameStart / 1000000;
+    }
+}
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index 4b7e0dd..01fe078 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -167,7 +167,7 @@
 }
 
 static jboolean
-android_hardware_UsbRequest_enqueue(JNIEnv *env, jobject thiz, jobject buffer, jint offset,
+android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset,
         jint length)
 {
     struct usb_request* request = get_request_from_object(env, thiz);
@@ -226,8 +226,8 @@
     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
                                             (void *)android_hardware_UsbRequest_init},
     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
-    {"native_enqueue",         "(Ljava/nio/ByteBuffer;II)Z",
-                                            (void *)android_hardware_UsbRequest_enqueue},
+    {"native_queue",            "(Ljava/nio/ByteBuffer;II)Z",
+                                            (void *)android_hardware_UsbRequest_queue},
     {"native_queue_array",      "([BIZ)Z",  (void *)android_hardware_UsbRequest_queue_array},
     {"native_dequeue_array",    "([BIZ)I",  (void *)android_hardware_UsbRequest_dequeue_array},
     {"native_queue_direct",     "(Ljava/nio/ByteBuffer;IZ)Z",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 8a7d1cf..bde9134 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -101,17 +101,7 @@
     return sur;
 }
 
-jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
-        const sp<IGraphicBufferProducer>& bufferProducer) {
-    if (bufferProducer == NULL) {
-        return NULL;
-    }
-
-    sp<Surface> surface(new Surface(bufferProducer, true));
-    if (surface == NULL) {
-        return NULL;
-    }
-
+jobject android_view_Surface_createFromSurface(JNIEnv* env, const sp<Surface>& surface) {
     jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
             gSurfaceClassInfo.ctor, (jlong)surface.get());
     if (surfaceObj == NULL) {
@@ -126,6 +116,16 @@
     return surfaceObj;
 }
 
+jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
+        const sp<IGraphicBufferProducer>& bufferProducer) {
+    if (bufferProducer == NULL) {
+        return NULL;
+    }
+
+    sp<Surface> surface(new Surface(bufferProducer, true));
+    return android_view_Surface_createFromSurface(env, surface);
+}
+
 int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f) {
 
     switch(f) {
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index d27c5a3..36487b3 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -70,6 +70,10 @@
 /* Gets the underlying Surface from a Surface Java object. */
 extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj);
 
+/* Creates a Surface from an android::Surface. */
+extern jobject android_view_Surface_createFromSurface(JNIEnv* env,
+        const sp<Surface>& surface);
+
 /* Creates a Surface from an IGraphicBufferProducer. */
 extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
         const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 48a460d..f1d8c98 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3370,7 +3370,8 @@
                 android:documentLaunchMode="never"
                 android:relinquishTaskIdentity="true"
                 android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3384,7 +3385,8 @@
                   android:documentLaunchMode="never"
                   android:relinquishTaskIdentity="true"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-                  android:process=":ui">
+                  android:process=":ui"
+                  android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3445,7 +3447,8 @@
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
@@ -3453,14 +3456,16 @@
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.CantAddAccountActivity"
@@ -3474,7 +3479,8 @@
                 android:excludeFromRecents="true"
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 554f50c..ee73b69 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8566,6 +8566,11 @@
         <!-- @hide From Theme.colorBackground, used for the TaskDescription background
                    color. -->
         <attr name="colorBackground" />
+        <!-- @hide From Theme.statusBarColor, used for the TaskDescription status bar color. -->
+        <attr name="statusBarColor"/>
+        <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
+                   color. -->
+        <attr name="navigationBarColor"/>
     </declare-styleable>
 
     <declare-styleable name="Shortcut">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 85ecaff..30625d0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2812,6 +2812,11 @@
     <!-- TODO(b/35230407) complete the link field -->
     <bool name="config_allowEscrowTokenForTrustAgent">false</bool>
 
+    <!-- A flattened ComponentName which corresponds to the only trust agent that should be enabled
+         by default. If the default value is used, or set to an empty string, the restriction will
+         not be applied. -->
+    <string name="config_defaultTrustAgent" translatable="false"></string>
+
     <!-- Colon separated list of package names that should be granted Notification Listener access -->
     <string name="config_defaultListenerAccessPackages" translatable="false"></string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae05a69..9ebbe29 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2890,6 +2890,7 @@
 
   <!-- android.service.trust -->
   <java-symbol type="bool" name="config_allowEscrowTokenForTrustAgent"/>
+  <java-symbol type="string" name="config_defaultTrustAgent" />
 
   <!-- Time picker -->
   <java-symbol type="id" name="toggle_mode"/>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 344f3c8..86ab3dc 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -181,6 +181,9 @@
     <allow-in-power-save package="com.android.cellbroadcastreceiver" />
     <allow-in-power-save package="com.android.shell" />
 
+    <!-- STOPSHIP(b/36856786): Revert this once it is fixed properly -->
+    <allow-in-power-save package="com.google.android.apps.enterprise.dmagent" />
+
     <!-- These are the packages that are white-listed to be able to run as system user -->
     <system-user-whitelisted-app package="com.android.settings" />
 
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 5973d3e..76eab4a 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -262,7 +262,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index d69f67d..218b857c 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -289,7 +289,7 @@
  * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p>
  */
 @AnyThread
-public final class Color {
+public class Color {
     @ColorInt public static final int BLACK       = 0xFF000000;
     @ColorInt public static final int DKGRAY      = 0xFF444444;
     @ColorInt public static final int GRAY        = 0xFF888888;
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index d603436..1b8336f 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -202,7 +202,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             dispose();
         } finally {
             super.finalize();
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index cd1f8de..245d769 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -270,7 +270,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             if (mInput != null) {
                 doClose();
             }
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 7b7a290..b7b81ae 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -230,7 +230,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             if (mInput != null) {
                 doClose();
             }
@@ -444,7 +447,10 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                mCloseGuard.warnIfOpen();
+                if (mCloseGuard != null) {
+                    mCloseGuard.warnIfOpen();
+                }
+
                 if (mNativePage != 0) {
                     doClose();
                 }
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0c7bb60..deea8a7 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -363,8 +363,15 @@
         }
         auto displayList = node->getDisplayList();
         if (displayList) {
-            for (auto&& childOp : displayList->getChildren()) {
-                syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode);
+            if (displayList->isSkiaDL()) {
+                for (auto&& childDr : static_cast<skiapipeline::SkiaDisplayList*>(
+                        const_cast<DisplayList*>(displayList))->mChildNodes) {
+                    syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode());
+                }
+            } else {
+                for (auto&& childOp : displayList->getChildren()) {
+                    syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode);
+                }
             }
         }
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c7796cd..4adbf79 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2540,6 +2540,44 @@
 
     /**
      * @hide
+     * Notifies an application with a focus listener of gain or loss of audio focus.
+     * This method can only be used by owners of an {@link AudioPolicy} configured with
+     * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
+     * @param afi the recipient of the focus change, that has previously requested audio focus, and
+     *     that was received by the {@code AudioPolicy} through
+     *     {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
+     * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
+     *     {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
+     *     {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
+     *     or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
+     *     {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
+     *     or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
+     *     <br>For the focus gain, the change type should be the same as the app requested.
+     * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
+     * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
+     *     {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
+     *     if there was an error sending the request.
+     * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
+     */
+    @SystemApi
+    public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
+            @NonNull AudioPolicy ap) {
+        if (afi == null) {
+            throw new NullPointerException("Illegal null AudioFocusInfo");
+        }
+        if (ap == null) {
+            throw new NullPointerException("Illegal null AudioPolicy");
+        }
+        final IAudioService service = getService();
+        try {
+            return service.dispatchFocusChange(afi, focusChange, ap.cb());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
      * Used internally by telephony package to abandon audio focus, typically after a call or
      * when ringing ends and the call is rejected or not answered.
      * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
@@ -2548,7 +2586,7 @@
         final IAudioService service = getService();
         try {
             service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
-                    null /*AudioAttributes, legacy behavior*/);
+                    null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2579,7 +2617,7 @@
         final IAudioService service = getService();
         try {
             status = service.abandonAudioFocus(mAudioFocusDispatcher,
-                    getIdForAudioFocusListener(l), aa);
+                    getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2787,7 +2825,7 @@
         final IAudioService service = getService();
         try {
             String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
-                    policy.hasFocusListener());
+                    policy.hasFocusListener(), policy.isFocusPolicy());
             if (regId == null) {
                 return ERROR;
             } else {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5855984..884d41e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRecordingConfiguration;
 import android.media.AudioRoutesInfo;
@@ -122,7 +123,8 @@
             IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
             IAudioPolicyCallback pcb);
 
-    int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa);
+    int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa,
+            in String callingPackageName);
 
     void unregisterAudioFocusClient(String clientId);
 
@@ -164,7 +166,7 @@
     boolean isHdmiSystemAudioSupported();
 
     String registerAudioPolicy(in AudioPolicyConfig policyConfig,
-            in IAudioPolicyCallback pcb, boolean hasFocusListener);
+            in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy);
 
     oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
 
@@ -196,5 +198,8 @@
 
     int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
 
+    int dispatchFocusChange(in AudioFocusInfo afi, in int focusChange,
+            in IAudioPolicyCallback pcb);
+
     // WARNING: read warning at top of file, it is recommended to add new methods at the end
 }
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index cdc1d60..4675e32 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -746,14 +746,19 @@
     }
 
     /**
-     * Sets the video encoding profile for recording. Call this method before prepare().
-     * Prepare() may perform additional checks on the parameter to make sure whether the
-     * specified profile and level are applicable, and sometimes the passed profile or
-     * level will be discarded due to codec capablity or to ensure the video recording
-     * can proceed smoothly based on the capabilities of the platform.
-     * @hide
+     * Sets the desired video encoding profile and level for recording. The profile and level
+     * must be valid for the video encoder set by {@link #setVideoEncoder}. This method can
+     * called before or after {@link #setVideoEncoder} but it must be called before {@link #prepare}.
+     * {@code prepare()} may perform additional checks on the parameter to make sure that the specified
+     * profile and level are applicable, and sometimes the passed profile or level will be
+     * discarded due to codec capablity or to ensure the video recording can proceed smoothly
+     * based on the capabilities of the platform. <br>Application can also use the
+     * {@link MediaCodecInfo.CodecCapabilities#profileLevels} to query applicable combination of profile
+     * and level for the corresponding format. Note that the requested profile/level may not be supported by
+     * the codec that is actually being used by this MediaRecorder instance.
      * @param profile declared in {@link MediaCodecInfo.CodecProfileLevel}.
      * @param level declared in {@link MediaCodecInfo.CodecProfileLevel}.
+     * @throws IllegalArgumentException when an invalid profile or level value is used.
      */
     public void setVideoEncodingProfileLevel(int profile, int level) {
         if (profile <= 0)  {
@@ -1281,3 +1286,4 @@
     @Override
     protected void finalize() { native_finalize(); }
 }
+
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index ddfa025..cb4e46f 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1958,7 +1958,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 423b467..61d642f 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -68,6 +68,7 @@
     private int mStatus;
     private String mRegistrationId;
     private AudioPolicyStatusListener mStatusListener;
+    private boolean mIsFocusPolicy;
 
     /**
      * The behavior of a policy with regards to audio focus where it relies on the application
@@ -96,12 +97,14 @@
     public AudioPolicyConfig getConfig() { return mConfig; }
     /** @hide */
     public boolean hasFocusListener() { return mFocusListener != null; }
+    /** @hide */
+    public boolean isFocusPolicy() { return mIsFocusPolicy; }
 
     /**
      * The parameter is guaranteed non-null through the Builder
      */
     private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper,
-            AudioPolicyFocusListener fl, AudioPolicyStatusListener sl) {
+            AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, boolean isFocusPolicy) {
         mConfig = config;
         mStatus = POLICY_STATUS_UNREGISTERED;
         mContext = context;
@@ -116,10 +119,12 @@
         }
         mFocusListener = fl;
         mStatusListener = sl;
+        mIsFocusPolicy = isFocusPolicy;
     }
 
     /**
-     * Builder class for {@link AudioPolicy} objects
+     * Builder class for {@link AudioPolicy} objects.
+     * By default the policy to be created doesn't govern audio focus decisions.
      */
     @SystemApi
     public static class Builder {
@@ -128,6 +133,7 @@
         private Looper mLooper;
         private AudioPolicyFocusListener mFocusListener;
         private AudioPolicyStatusListener mStatusListener;
+        private boolean mIsFocusPolicy = false;
 
         /**
          * Constructs a new Builder with no audio mixes.
@@ -179,6 +185,21 @@
         }
 
         /**
+         * Declares whether this policy will grant and deny audio focus through
+         * the {@link AudioPolicy.AudioPolicyStatusListener}.
+         * If set to {@code true}, it is mandatory to set an
+         * {@link AudioPolicy.AudioPolicyStatusListener} in order to successfully build
+         * an {@code AudioPolicy} instance.
+         * @param enforce true if the policy will govern audio focus decisions.
+         * @return the same Builder instance.
+         */
+        @SystemApi
+        public Builder setIsAudioFocusPolicy(boolean isFocusPolicy) {
+            mIsFocusPolicy = isFocusPolicy;
+            return this;
+        }
+
+        /**
          * Sets the audio policy status listener.
          * @param l a {@link AudioPolicy.AudioPolicyStatusListener}
          */
@@ -187,6 +208,14 @@
             mStatusListener = l;
         }
 
+        /**
+         * Combines all of the attributes that have been set on this {@code Builder} and returns a
+         * new {@link AudioPolicy} object.
+         * @return a new {@code AudioPolicy} object.
+         * @throws IllegalStateException if there is no
+         *     {@link AudioPolicy.AudioPolicyStatusListener} but the policy was configured
+         *     as an audio focus policy with {@link #setIsAudioFocusPolicy(boolean)}.
+         */
         @SystemApi
         public AudioPolicy build() {
             if (mStatusListener != null) {
@@ -195,8 +224,12 @@
                     mix.mCallbackFlags |= AudioMix.CALLBACK_FLAG_NOTIFY_ACTIVITY;
                 }
             }
+            if (mIsFocusPolicy && mFocusListener == null) {
+                throw new IllegalStateException("Cannot be a focus policy without "
+                        + "an AudioPolicyFocusListener");
+            }
             return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
-                    mFocusListener, mStatusListener);
+                    mFocusListener, mStatusListener, mIsFocusPolicy);
         }
     }
 
@@ -402,6 +435,24 @@
     public static abstract class AudioPolicyFocusListener {
         public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {}
         public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {}
+        /**
+         * Called whenever an application requests audio focus.
+         * Only ever called if the {@link AudioPolicy} was built with
+         * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.
+         * @param afi information about the focus request and the requester
+         * @param requestResult the result that was returned synchronously by the framework to the
+         *     application, {@link #AUDIOFOCUS_REQUEST_FAILED},or
+         *     {@link #AUDIOFOCUS_REQUEST_DELAYED}.
+         */
+        public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {}
+        /**
+         * Called whenever an application abandons audio focus.
+         * Only ever called if the {@link AudioPolicy} was built with
+         * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.
+         * @param afi information about the focus request being abandoned and the original
+         *     requester.
+         */
+        public void onAudioFocusAbandon(AudioFocusInfo afi) {}
     }
 
     private void onPolicyStatusChange() {
@@ -439,6 +490,22 @@
             }
         }
 
+        public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
+            sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
+            if (DEBUG) {
+                Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
+                        + afi.getClientId() + "reqRes=" + requestResult);
+            }
+        }
+
+        public void notifyAudioFocusAbandon(AudioFocusInfo afi) {
+            sendMsg(MSG_FOCUS_ABANDON, afi, 0 /* ignored */);
+            if (DEBUG) {
+                Log.v(TAG, "notifyAudioFocusAbandon: pack=" + afi.getPackageName() + " client="
+                        + afi.getClientId());
+            }
+        }
+
         public void notifyMixStateUpdate(String regId, int state) {
             for (AudioMix mix : mConfig.getMixes()) {
                 if (mix.getRegistration().equals(regId)) {
@@ -459,6 +526,8 @@
     private final static int MSG_FOCUS_GRANT = 1;
     private final static int MSG_FOCUS_LOSS = 2;
     private final static int MSG_MIX_STATE_UPDATE = 3;
+    private final static int MSG_FOCUS_REQUEST = 4;
+    private final static int MSG_FOCUS_ABANDON = 5;
 
     private class EventHandler extends Handler {
         public EventHandler(AudioPolicy ap, Looper looper) {
@@ -488,6 +557,20 @@
                         mStatusListener.onMixStateUpdate((AudioMix) msg.obj);
                     }
                     break;
+                case MSG_FOCUS_REQUEST:
+                    if (mFocusListener != null) {
+                        mFocusListener.onAudioFocusRequest((AudioFocusInfo) msg.obj, msg.arg1);
+                    } else { // should never be null, but don't crash
+                        Log.e(TAG, "Invalid null focus listener for focus request event");
+                    }
+                    break;
+                case MSG_FOCUS_ABANDON:
+                    if (mFocusListener != null) { // should never be null
+                        mFocusListener.onAudioFocusAbandon((AudioFocusInfo) msg.obj);
+                    } else { // should never be null, but don't crash
+                        Log.e(TAG, "Invalid null focus listener for focus abandon event");
+                    }
+                    break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what);
             }
diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
index ad8af15..86abbb4 100644
--- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
+++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
@@ -22,9 +22,12 @@
  */
 oneway interface IAudioPolicyCallback {
 
-    // callbacks for audio focus
+    // callbacks for audio focus listening
     void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult);
     void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified);
+    // callback for audio focus policy
+    void notifyAudioFocusRequest(in AudioFocusInfo afi, int requestResult);
+    void notifyAudioFocusAbandon(in AudioFocusInfo afi);
 
     // callback for mix activity status update
     void notifyMixStateUpdate(in String regId, int state);
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index f7dd0b3..a995736 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -103,7 +103,10 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                mGuard.warnIfOpen();
+                if (mGuard != null) {
+                    mGuard.warnIfOpen();
+                }
+
                 close();
             } finally {
                 super.finalize();
@@ -285,7 +288,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mGuard.warnIfOpen();
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index eaa8654..51d5520 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -429,7 +429,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mGuard.warnIfOpen();
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
index 98ec779..a300886 100644
--- a/media/java/android/media/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -159,7 +159,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mGuard.warnIfOpen();
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+            }
+
             // not safe to make binder calls from finalize()
             mDeviceServer = null;
             close();
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
index ce0402c..511f6cd 100644
--- a/media/java/android/media/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -145,7 +145,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mGuard.warnIfOpen();
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+            }
+
             // not safe to make binder calls from finalize()
             mDeviceServer = null;
             close();
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 06fc4bc..d8c3eca 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
@@ -840,7 +841,7 @@
     public interface BasePreviewProgramColumns extends BaseProgramColumns {
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 TYPE_MOVIE,
                 TYPE_TV_SERIES,
                 TYPE_TV_SEASON,
@@ -862,87 +863,87 @@
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_MOVIE = "TYPE_MOVIE";
+        int TYPE_MOVIE = 0;
 
         /**
          * The program type for TV series.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+        int TYPE_TV_SERIES = 1;
 
         /**
          * The program type for TV season.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+        int TYPE_TV_SEASON = 2;
 
         /**
          * The program type for TV episode.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+        int TYPE_TV_EPISODE = 3;
 
         /**
          * The program type for clip.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_CLIP = "TYPE_CLIP";
+        int TYPE_CLIP = 4;
 
         /**
          * The program type for event.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_EVENT = "TYPE_EVENT";
+        int TYPE_EVENT = 5;
 
         /**
          * The program type for channel.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_CHANNEL = "TYPE_CHANNEL";
+        int TYPE_CHANNEL = 6;
 
         /**
          * The program type for track.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_TRACK = "TYPE_TRACK";
+        int TYPE_TRACK = 7;
 
         /**
          * The program type for album.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_ALBUM = "TYPE_ALBUM";
+        int TYPE_ALBUM = 8;
 
         /**
          * The program type for artist.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_ARTIST = "TYPE_ARTIST";
+        int TYPE_ARTIST = 9;
 
         /**
          * The program type for playlist.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+        int TYPE_PLAYLIST = 10;
 
         /**
          * The program type for station.
          *
          * @see #COLUMN_TYPE
          */
-        String TYPE_STATION = "TYPE_STATION";
+        int TYPE_STATION = 11;
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 ASPECT_RATIO_16_9,
                 ASPECT_RATIO_3_2,
                 ASPECT_RATIO_1_1,
@@ -957,7 +958,7 @@
          * @see #COLUMN_POSTER_ART_ASPECT_RATIO
          * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
          */
-        String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+        int ASPECT_RATIO_16_9 = 0;
 
         /**
          * The aspect ratio for 3:2.
@@ -965,7 +966,7 @@
          * @see #COLUMN_POSTER_ART_ASPECT_RATIO
          * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
          */
-        String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+        int ASPECT_RATIO_3_2 = 1;
 
         /**
          * The aspect ratio for 1:1.
@@ -973,7 +974,7 @@
          * @see #COLUMN_POSTER_ART_ASPECT_RATIO
          * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
          */
-        String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+        int ASPECT_RATIO_1_1 = 2;
 
         /**
          * The aspect ratio for 2:3.
@@ -981,10 +982,10 @@
          * @see #COLUMN_POSTER_ART_ASPECT_RATIO
          * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
          */
-        String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+        int ASPECT_RATIO_2_3 = 3;
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 AVAILABILITY_AVAILABLE,
                 AVAILABILITY_FREE_WITH_SUBSCRIPTION,
                 AVAILABILITY_PAID_CONTENT,
@@ -997,15 +998,14 @@
          *
          * @see #COLUMN_AVAILABILITY
          */
-        String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+        int AVAILABILITY_AVAILABLE = 0;
 
         /**
          * The availability for "free with subscription".
          *
          * @see #COLUMN_AVAILABILITY
          */
-        String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
-                "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+        int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1;
 
         /**
          * The availability for "paid content, either to-own or rental
@@ -1013,72 +1013,72 @@
          *
          * @see #COLUMN_AVAILABILITY
          */
-        String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+        int AVAILABILITY_PAID_CONTENT = 2;
 
         /** @hide */
-        @StringDef({
+        @IntDef({
+                INTERACTION_TYPE_VIEWS,
                 INTERACTION_TYPE_LISTENS,
                 INTERACTION_TYPE_FOLLOWERS,
                 INTERACTION_TYPE_FANS,
                 INTERACTION_TYPE_LIKES,
                 INTERACTION_TYPE_THUMBS,
-                INTERACTION_TYPE_VIEWS,
                 INTERACTION_TYPE_VIEWERS,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface InteractionType {}
 
         /**
+         * The interaction type for "views".
+         *
+         * @see #COLUMN_INTERACTION_TYPE
+         */
+        int INTERACTION_TYPE_VIEWS = 0;
+
+        /**
          * The interaction type for "listens".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+        int INTERACTION_TYPE_LISTENS = 1;
 
         /**
          * The interaction type for "followers".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+        int INTERACTION_TYPE_FOLLOWERS = 2;
 
         /**
          * The interaction type for "fans".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+        int INTERACTION_TYPE_FANS = 3;
 
         /**
          * The interaction type for "likes".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+        int INTERACTION_TYPE_LIKES = 4;
 
         /**
          * The interaction type for "thumbs".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-
-        /**
-         * The interaction type for "views".
-         *
-         * @see #COLUMN_INTERACTION_TYPE
-         */
-        String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+        int INTERACTION_TYPE_THUMBS = 5;
 
         /**
          * The interaction type for "viewers".
          *
          * @see #COLUMN_INTERACTION_TYPE
          */
-        String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+        int INTERACTION_TYPE_VIEWERS = 6;
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 REVIEW_RATING_STYLE_STARS,
                 REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
                 REVIEW_RATING_STYLE_PERCENTAGE,
@@ -1091,23 +1091,21 @@
          *
          * @see #COLUMN_REVIEW_RATING_STYLE
          */
-        String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+        int REVIEW_RATING_STYLE_STARS = 0;
 
         /**
          * The review rating style for thumbs-up and thumbs-down rating.
          *
          * @see #COLUMN_REVIEW_RATING_STYLE
          */
-        String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
-                "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+        int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1;
 
         /**
          * The review rating style for 0 to 100 point system.
          *
          * @see #COLUMN_REVIEW_RATING_STYLE
          */
-        String REVIEW_RATING_STYLE_PERCENTAGE =
-                "REVIEW_RATING_STYLE_PERCENTAGE";
+        int REVIEW_RATING_STYLE_PERCENTAGE = 2;
 
         /**
          * The type of this program content.
@@ -1129,7 +1127,7 @@
          * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
          * channel.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         String COLUMN_TYPE = "type";
 
@@ -1142,7 +1140,7 @@
          * {@link #ASPECT_RATIO_1_1}, and
          * {@link #ASPECT_RATIO_2_3}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
 
@@ -1155,7 +1153,7 @@
          * {@link #ASPECT_RATIO_1_1}, and
          * {@link #ASPECT_RATIO_2_3}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
 
@@ -1188,7 +1186,7 @@
          * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
          * {@link #AVAILABILITY_PAID_CONTENT}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         String COLUMN_AVAILABILITY = "availability";
 
@@ -1299,18 +1297,17 @@
         String COLUMN_DURATION_MILLIS = "duration_millis";
 
         /**
-         * The intent URI which is launched when the preview video is selected.
+         * The intent URI which is launched when the preview program is selected.
          *
          * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
          * and converted back to the original intent with {@link Intent#parseUri}. The intent is
-         * launched when the user selects the preview video item.
+         * launched when the user selects the preview program item.
          *
          * <p>Can be empty.
          *
          * <p>Type: TEXT
          */
-        String COLUMN_APP_LINK_INTENT_URI =
-                "app_link_intent_uri";
+        String COLUMN_INTENT_URI = "intent_uri";
 
         /**
          * The flag indicating whether this program is transient or not.
@@ -1328,15 +1325,15 @@
          * The type of interaction for this TV program.
          *
          * <p> The value should match one of the followings:
+         * {@link #INTERACTION_TYPE_VIEWS},
          * {@link #INTERACTION_TYPE_LISTENS},
          * {@link #INTERACTION_TYPE_FOLLOWERS},
          * {@link #INTERACTION_TYPE_FANS},
          * {@link #INTERACTION_TYPE_LIKES},
-         * {@link #INTERACTION_TYPE_THUMBS},
-         * {@link #INTERACTION_TYPE_VIEWS}, and
+         * {@link #INTERACTION_TYPE_THUMBS}, and
          * {@link #INTERACTION_TYPE_VIEWERS}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          * @see #COLUMN_INTERACTION_COUNT
          */
         String COLUMN_INTERACTION_TYPE = "interaction_type";
@@ -1364,7 +1361,7 @@
          * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
          * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          * @see #COLUMN_REVIEW_RATING
          */
         String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
@@ -2725,7 +2722,7 @@
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 WATCH_NEXT_TYPE_CONTINUE,
                 WATCH_NEXT_TYPE_NEXT,
                 WATCH_NEXT_TYPE_NEW,
@@ -2740,7 +2737,7 @@
          *
          * @see #COLUMN_WATCH_NEXT_TYPE
          */
-        public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+        public static final int WATCH_NEXT_TYPE_CONTINUE = 0;
 
         /**
          * The watch next type for NEXT. Use this type when the user has watched one or more
@@ -2750,7 +2747,7 @@
          *
          * @see #COLUMN_WATCH_NEXT_TYPE
          */
-        public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+        public static final int WATCH_NEXT_TYPE_NEXT = 1;
 
         /**
          * The watch next type for NEW. Use this type when the user had watched all of the available
@@ -2760,7 +2757,7 @@
          *
          * @see #COLUMN_WATCH_NEXT_TYPE
          */
-        public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+        public static final int WATCH_NEXT_TYPE_NEW = 2;
 
         /**
          * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly
@@ -2769,7 +2766,7 @@
          *
          * @see #COLUMN_WATCH_NEXT_TYPE
          */
-        public static final String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+        public static final int WATCH_NEXT_TYPE_WATCHLIST = 3;
 
         /**
          * The "watch next" type of this program content.
@@ -2782,7 +2779,7 @@
          *
          * <p>This is a required field.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 56a5737..698c9c9 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -233,7 +233,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index d6958b3..e8b04ed 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -123,7 +123,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             close();
         } finally {
             super.finalize();
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index c7bed9b..c82a1f6 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -153,6 +153,7 @@
     ANativeWindow_acquire;
     ANativeWindow_fromSurface;
     ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13
+    ANativeWindow_toSurface; # introduced=26
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getWidth;
diff --git a/native/android/native_window_jni.cpp b/native/android/native_window_jni.cpp
index dc30405..859c550 100644
--- a/native/android/native_window_jni.cpp
+++ b/native/android/native_window_jni.cpp
@@ -20,6 +20,7 @@
 #include <android/native_window.h>
 #include <system/window.h>
 
+#include <gui/Surface.h>
 #include <utils/StrongPointer.h>
 
 #include <android_runtime/android_view_Surface.h>
@@ -33,3 +34,11 @@
     }
     return win.get();
 }
+
+jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) {
+    if (window == NULL) {
+        return NULL;
+    }
+    sp<Surface> surface = static_cast<Surface*>(window);
+    return android_view_Surface_createFromSurface(env, surface);
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 14b9de5..13f82dd 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -34,6 +34,7 @@
 import android.widget.TextView;
 
 import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair;
+import com.android.internal.util.Preconditions;
 
 public class DeviceChooserActivity extends Activity {
 
@@ -92,8 +93,11 @@
     private CharSequence getCallingAppName() {
         try {
             final PackageManager packageManager = getPackageManager();
+            String callingPackage = Preconditions.checkStringNotEmpty(
+                    getCallingPackage(),
+                    "This activity must be called for result");
             return packageManager.getApplicationLabel(
-                    packageManager.getApplicationInfo(getCallingPackage(), 0));
+                    packageManager.getApplicationInfo(callingPackage, 0));
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(e);
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index 6140428..653a453 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -171,8 +171,11 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mState != STATE_DESTROYED) {
+            if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
+            }
+
+            if (mState != STATE_DESTROYED) {
                 destroy(null);
             }
         } finally {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 54400b3..e172948 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -552,8 +552,11 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mState != STATE_DESTROYED) {
+            if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
+            }
+
+            if (mState != STATE_DESTROYED) {
                 destroy(null);
             }
         } finally {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f14d0d1..ad985c7 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -928,4 +928,18 @@
          [CHAR LIMIT=35] -->
     <string name="use_system_language_to_select_input_method_subtypes">Use system languages</string>
 
+    <!-- Toast that settings for an application is failed to open. -->
+    <string name="failed_to_open_app_settings_toast">Failed to open settings for <xliff:g id="spell_application_name">%1$s</xliff:g></string>
+
+    <!-- Warning message about security implications of enabling an input method, displayed as a dialog
+         message when the user selects to enable an IME. -->
+    <string name="ime_security_warning">This input method may be able to collect
+        all the text you type, including personal data like passwords and credit
+        card numbers.  It comes from the app
+        <xliff:g id="ime_application_name">%1$s</xliff:g>.
+        Use this input method?</string>
+
+    <!-- [CHAR LIMIT=NONE] Dialog body explaining that the app just selected by the user will not work after a reboot until until after the user enters their credentials, such as a PIN or password. -->
+    <string name="direct_boot_unaware_dialog_message">Note: After a reboot, this app can\'t start until you unlock your phone</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 77f2e19..a1c8de5 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -122,9 +122,6 @@
                     return true;
                 }
             }
-            for (BluetoothDevice src : srcs) {
-                mService.disconnect(src);
-            }
         }
         return mService.connect(device);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
index 69b45e5..9ea7a4a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
@@ -71,14 +71,15 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        if (intent.getAction() == null || !intent.getAction().equals(INTENT_DISCOVERABLE_TIMEOUT)) {
+            return;
+        }
         LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance();
-
-         if(localBluetoothAdapter != null  &&
+        if(localBluetoothAdapter != null  &&
             localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
             Log.d(TAG, "Disable discoverable...");
-
             localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
-         } else {
+        } else {
             Log.e(TAG, "localBluetoothAdapter is NULL!!");
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index a3ae926..abd4e29 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -103,7 +103,7 @@
      */
     public String getName(BluetoothDevice device) {
         CachedBluetoothDevice cachedDevice = findDevice(device);
-        if (cachedDevice != null) {
+        if (cachedDevice != null && cachedDevice.getName() != null) {
             return cachedDevice.getName();
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 9b699bc..169aac9 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -132,11 +132,6 @@
                     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);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index a7621fc..6efa468 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -115,10 +115,10 @@
     public boolean connect(BluetoothDevice device) {
         if (mService == null) return false;
         List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        if (connectedDevices != null) {
-            for (BluetoothDevice connectedDevice : connectedDevices) {
-                mService.disconnect(connectedDevice);
-            }
+        if (connectedDevices != null && connectedDevices.contains(device)) {
+            // Connect to same device, Ignore it
+            Log.d(TAG,"Ignoring Connect");
+            return true;
         }
         return mService.connect(device);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 72a3b3a..bd37abe 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -144,9 +144,6 @@
                     return true;
                 }
             }
-            for (BluetoothDevice src : srcs) {
-                mService.disconnect(src);
-            }
         }
         Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
new file mode 100755
index 0000000..1bbc878b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.inputmethod;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.Toast;
+
+import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.settingslib.R;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import java.text.Collator;
+import java.util.List;
+
+/**
+ * Input method preference.
+ *
+ * This preference represents an IME. It is used for two purposes. 1) An instance with a switch
+ * is used to enable or disable the IME. 2) An instance without a switch is used to invoke the
+ * setting activity of the IME.
+ */
+public class InputMethodPreference extends RestrictedSwitchPreference implements OnPreferenceClickListener,
+        OnPreferenceChangeListener {
+    private static final String TAG = InputMethodPreference.class.getSimpleName();
+    private static final String EMPTY_TEXT = "";
+    private static final int NO_WIDGET = 0;
+
+    public interface OnSavePreferenceListener {
+        /**
+         * Called when this preference needs to be saved its state.
+         *
+         * Note that this preference is non-persistent and needs explicitly to be saved its state.
+         * Because changing one IME state may change other IMEs' state, this is a place to update
+         * other IMEs' state as well.
+         *
+         * @param pref This preference.
+         */
+        void onSaveInputMethodPreference(InputMethodPreference pref);
+    }
+
+    private final InputMethodInfo mImi;
+    private final boolean mHasPriorityInSorting;
+    private final OnSavePreferenceListener mOnSaveListener;
+    private final InputMethodSettingValuesWrapper mInputMethodSettingValues;
+    private final boolean mIsAllowedByOrganization;
+
+    private AlertDialog mDialog = null;
+
+    /**
+     * A preference entry of an input method.
+     *
+     * @param context The Context this is associated with.
+     * @param imi The {@link InputMethodInfo} of this preference.
+     * @param isImeEnabler true if this preference is the IME enabler that has enable/disable
+     *     switches for all available IMEs, not the list of enabled IMEs.
+     * @param isAllowedByOrganization false if the IME has been disabled by a device or profile
+     *     owner.
+     * @param onSaveListener The listener called when this preference has been changed and needs
+     *     to save the state to shared preference.
+     */
+    public InputMethodPreference(final Context context, final InputMethodInfo imi,
+            final boolean isImeEnabler, final boolean isAllowedByOrganization,
+            final OnSavePreferenceListener onSaveListener) {
+        super(context);
+        setPersistent(false);
+        mImi = imi;
+        mIsAllowedByOrganization = isAllowedByOrganization;
+        mOnSaveListener = onSaveListener;
+        if (!isImeEnabler) {
+            // Remove switch widget.
+            setWidgetLayoutResource(NO_WIDGET);
+        }
+        // Disable on/off switch texts.
+        setSwitchTextOn(EMPTY_TEXT);
+        setSwitchTextOff(EMPTY_TEXT);
+        setKey(imi.getId());
+        setTitle(imi.loadLabel(context.getPackageManager()));
+        final String settingsActivity = imi.getSettingsActivity();
+        if (TextUtils.isEmpty(settingsActivity)) {
+            setIntent(null);
+        } else {
+            // Set an intent to invoke settings activity of an input method.
+            final Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClassName(imi.getPackageName(), settingsActivity);
+            setIntent(intent);
+        }
+        mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(context);
+        mHasPriorityInSorting = InputMethodUtils.isSystemIme(imi)
+                && mInputMethodSettingValues.isValidSystemNonAuxAsciiCapableIme(imi, context);
+        setOnPreferenceClickListener(this);
+        setOnPreferenceChangeListener(this);
+    }
+
+    public InputMethodInfo getInputMethodInfo() {
+        return mImi;
+    }
+
+    private boolean isImeEnabler() {
+        // If this {@link SwitchPreference} doesn't have a widget layout, we explicitly hide the
+        // switch widget at constructor.
+        return getWidgetLayoutResource() != NO_WIDGET;
+    }
+
+    @Override
+    public boolean onPreferenceChange(final Preference preference, final Object newValue) {
+        // Always returns false to prevent default behavior.
+        // See {@link TwoStatePreference#onClick()}.
+        if (!isImeEnabler()) {
+            // Prevent disabling an IME because this preference is for invoking a settings activity.
+            return false;
+        }
+        if (isChecked()) {
+            // Disable this IME.
+            setCheckedInternal(false);
+            return false;
+        }
+        if (InputMethodUtils.isSystemIme(mImi)) {
+            // Enable a system IME. No need to show a security warning dialog,
+            // but we might need to prompt if it's not Direct Boot aware.
+            // TV doesn't doesn't need to worry about this, but other platforms should show
+            // a warning.
+            if (mImi.getServiceInfo().directBootAware || isTv()) {
+                setCheckedInternal(true);
+            } else if (!isTv()){
+                showDirectBootWarnDialog();
+            }
+        } else {
+            // Once security is confirmed, we might prompt if the IME isn't
+            // Direct Boot aware.
+            showSecurityWarnDialog();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onPreferenceClick(final Preference preference) {
+        // Always returns true to prevent invoking an intent without catching exceptions.
+        // See {@link Preference#performClick(PreferenceScreen)}/
+        if (isImeEnabler()) {
+            // Prevent invoking a settings activity because this preference is for enabling and
+            // disabling an input method.
+            return true;
+        }
+        final Context context = getContext();
+        try {
+            final Intent intent = getIntent();
+            if (intent != null) {
+                // Invoke a settings activity of an input method.
+                context.startActivity(intent);
+            }
+        } catch (final ActivityNotFoundException e) {
+            Log.d(TAG, "IME's Settings Activity Not Found", e);
+            final String message = context.getString(
+                    R.string.failed_to_open_app_settings_toast,
+                    mImi.loadLabel(context.getPackageManager()));
+            Toast.makeText(context, message, Toast.LENGTH_LONG).show();
+        }
+        return true;
+    }
+
+    public void updatePreferenceViews() {
+        final boolean isAlwaysChecked = mInputMethodSettingValues.isAlwaysCheckedIme(
+                mImi, getContext());
+        // When this preference has a switch and an input method should be always enabled,
+        // this preference should be disabled to prevent accidentally disabling an input method.
+        // This preference should also be disabled in case the admin does not allow this input
+        // method.
+        if (isAlwaysChecked && isImeEnabler()) {
+            setDisabledByAdmin(null);
+            setEnabled(false);
+        } else if (!mIsAllowedByOrganization) {
+            EnforcedAdmin admin =
+                    RestrictedLockUtils.checkIfInputMethodDisallowed(getContext(),
+                            mImi.getPackageName(), UserHandle.myUserId());
+            setDisabledByAdmin(admin);
+        } else {
+            setEnabled(true);
+        }
+        setChecked(mInputMethodSettingValues.isEnabledImi(mImi));
+        if (!isDisabledByAdmin()) {
+            setSummary(getSummaryString());
+        }
+    }
+
+    private InputMethodManager getInputMethodManager() {
+        return (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+    }
+
+    private String getSummaryString() {
+        final InputMethodManager imm = getInputMethodManager();
+        final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(mImi, true);
+        return InputMethodAndSubtypeUtil.getSubtypeLocaleNameListAsSentence(
+                subtypes, getContext(), mImi);
+    }
+
+    private void setCheckedInternal(boolean checked) {
+        super.setChecked(checked);
+        mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
+        notifyChanged();
+    }
+
+    private void showSecurityWarnDialog() {
+        if (mDialog != null && mDialog.isShowing()) {
+            mDialog.dismiss();
+        }
+        final Context context = getContext();
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        builder.setCancelable(true /* cancelable */);
+        builder.setTitle(android.R.string.dialog_alert_title);
+        final CharSequence label = mImi.getServiceInfo().applicationInfo.loadLabel(
+                context.getPackageManager());
+        builder.setMessage(context.getString(R.string.ime_security_warning, label));
+        builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
+            // The user confirmed to enable a 3rd party IME, but we might
+            // need to prompt if it's not Direct Boot aware.
+            // TV doesn't doesn't need to worry about this, but other platforms should show
+            // a warning.
+            if (mImi.getServiceInfo().directBootAware || isTv()) {
+                setCheckedInternal(true);
+            } else {
+                showDirectBootWarnDialog();
+            }
+        });
+        builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
+            // The user canceled to enable a 3rd party IME.
+            setCheckedInternal(false);
+        });
+        mDialog = builder.create();
+        mDialog.show();
+    }
+
+    private boolean isTv() {
+        return (getContext().getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
+    }
+
+    private void showDirectBootWarnDialog() {
+        if (mDialog != null && mDialog.isShowing()) {
+            mDialog.dismiss();
+        }
+        final Context context = getContext();
+        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        builder.setCancelable(true /* cancelable */);
+        builder.setMessage(context.getText(R.string.direct_boot_unaware_dialog_message));
+        builder.setPositiveButton(android.R.string.ok, (dialog, which) -> setCheckedInternal(true));
+        builder.setNegativeButton(android.R.string.cancel,
+                (dialog, which) -> setCheckedInternal(false));
+        mDialog = builder.create();
+        mDialog.show();
+    }
+
+    public int compareTo(final InputMethodPreference rhs, final Collator collator) {
+        if (this == rhs) {
+            return 0;
+        }
+        if (mHasPriorityInSorting == rhs.mHasPriorityInSorting) {
+            final CharSequence t0 = getTitle();
+            final CharSequence t1 = rhs.getTitle();
+            if (TextUtils.isEmpty(t0)) {
+                return 1;
+            }
+            if (TextUtils.isEmpty(t1)) {
+                return -1;
+            }
+            return collator.compare(t0.toString(), t1.toString());
+        }
+        // Prefer always checked system IMEs
+        return mHasPriorityInSorting ? -1 : 1;
+    }
+}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ad39f54..a8cf3da 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1962,4 +1962,31 @@
     <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
     <string name="mobile_data">Mobile data</string>
 
+    <!-- Label for when wifi is off in QS detail panel [CHAR LIMIT=NONE] -->
+    <string name="wifi_is_off">Wi-Fi is off</string>
+
+    <!-- Label for when bluetooth is off in QS detail panel [CHAR LIMIT=NONE] -->
+    <string name="bt_is_off">Bluetooth is off</string>
+
+    <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] -->
+    <string name="dnd_is_off">Do Not Disturb is off</string>
+
+    <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>). Keep current settings?</string>
+
+    <!-- Prompt for when Do not disturb is on from app in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_app">Do Not Disturb was turned on by an app (<xliff:g name="app">%s</xliff:g>). Keep current settings?</string>
+
+    <!-- Prompt for when Do not disturb is on from automatic rule or app in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_auto_rule_app">Do Not Disturb was turned on by an automatic rule or app. Keep current settings?</string>
+
+    <!-- Description of Do Not Disturb option in QS that ends at the specified time[CHAR LIMIT=20] -->
+    <string name="qs_dnd_until">Until <xliff:g name="time">%s</xliff:g></string>
+
+    <!-- Do Not Disturb button to keep the current settings [CHAR LIMIT=20] -->
+    <string name="qs_dnd_keep">Keep</string>
+
+    <!-- Do Not Disturb button to change the current settings [CHAR LIMIT=20] -->
+    <string name="qs_dnd_replace">Replace</string>
+
 </resources>
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 1c71da0..3a43d30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -355,9 +355,10 @@
                 rti.firstActiveTime = rti.lastActiveTime = i;
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
-                        Bitmap.createBitmap(mDummyIcon), null,
-                        0xFF000000 | (0xFFFFFF & new Random().nextInt()),
-                        0xFF000000 | (0xFFFFFF & new Random().nextInt()));
+                            Bitmap.createBitmap(mDummyIcon), null,
+                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
+                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
+                            0, 0);
                 } else {
                     rti.taskDescription = new ActivityManager.TaskDescription();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 97506e6..0ee3e19 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -58,6 +58,7 @@
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.internal.policy.DockedDividerUtils;
+import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
@@ -108,9 +109,6 @@
     private static final Interpolator IME_ADJUST_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
-    private static final long ONE_MS_IN_NS = 1000000;
-    private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000;
-
     private static final int MSG_RESIZE_STACK = 0;
 
     private DividerHandleView mHandle;
@@ -161,12 +159,7 @@
     private boolean mHomeStackResizable;
     private boolean mAdjustedForIme;
     private DividerState mState;
-
-    /**
-     * The offset between vsync-app and vsync-surfaceflinger. See
-     * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary.
-     */
-    private long mSurfaceFlingerOffsetMs;
+    private SurfaceFlingerVsyncChoreographer mSfChoreographer;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -319,7 +312,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         EventBus.getDefault().register(this);
-        mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs();
+        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay());
     }
 
     @Override
@@ -328,25 +321,6 @@
         EventBus.getDefault().unregister(this);
     }
 
-    /**
-     * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app
-     * is a couple of milliseconds before vsync-sf, a touch or animation event that causes the
-     * stacks to be resized are sometimes processed before the vsync-sf tick, and sometimes after,
-     * which leads to jank. Figure out this difference here and then post all the touch/animation
-     * events to start being processed at vsync-sf.
-     *
-     * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf.
-     */
-    private long calculateAppSurfaceFlingerVsyncOffsetMs() {
-        Display display = getDisplay();
-
-        // Calculate vsync offset from SurfaceFlinger.
-        // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs
-        long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate());
-        long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS);
-        return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS);
-    }
-
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         if (mStableInsets.left != insets.getStableInsetLeft()
@@ -630,8 +604,8 @@
                     delay = endDelay;
                 } else if (mCancelled) {
                     delay = 0;
-                } else if (mSurfaceFlingerOffsetMs != 0) {
-                    delay = mSurfaceFlingerOffsetMs;
+                } else if (mSfChoreographer.getSurfaceFlingerOffsetMs() > 0) {
+                    delay = mSfChoreographer.getSurfaceFlingerOffsetMs();
                 }
                 if (delay == 0) {
                     endAction.run();
@@ -916,14 +890,10 @@
     }
 
     public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) {
-        if (mSurfaceFlingerOffsetMs != 0) {
-            Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition,
-                    taskSnapTarget);
-            message.setAsynchronous(true);
-            mHandler.sendMessageDelayed(message, mSurfaceFlingerOffsetMs);
-        } else {
-            resizeStack(position, taskPosition, taskSnapTarget);
-        }
+        Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition,
+                taskSnapTarget);
+        message.setAsynchronous(true);
+        mSfChoreographer.scheduleAtSfVsync(mHandler, message);
     }
 
     public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index f6d91f4..c4a2831 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -165,6 +165,14 @@
     // Package: android
     NOTE_NET_LIMIT_SNOOZED = 36;
 
+    // Inform the user they need to sign in to an account
+    // Package: android, and others
+    NOTE_ACCOUNT_REQUIRE_SIGNIN = 37;
+
+    // Inform the user that there has been a permission request for an account
+    // Package: android
+    NOTE_ACCOUNT_CREDENTIAL_PERMISSION = 38;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
@@ -216,9 +224,5 @@
     // Notify the user that data or apps are being moved to external storage.
     // Package: com.android.systemui
     NOTE_STORAGE_MOVE = 0x534d4f56;
-
-    // Account Manager allocates IDs sequentially, starting here.
-    // Package: android
-    ACCOUNT_MANAGER_BASE = 0x70000000;
   }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 087c248..1968d2e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -585,17 +585,12 @@
             result = mEnabledServicesForFeedbackTempList;
             result.clear();
             List<Service> services = userState.mBoundServices;
-            while (feedbackType != 0) {
-                final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
-                feedbackType &= ~feedbackTypeBit;
-                final int serviceCount = services.size();
-                for (int i = 0; i < serviceCount; i++) {
-                    Service service = services.get(i);
-                    // Don't report the UIAutomation (fake service)
-                    if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
-                            && (service.mFeedbackType & feedbackTypeBit) != 0) {
-                        result.add(service.mAccessibilityServiceInfo);
-                    }
+            for (int serviceCount = services.size(), i = 0; i < serviceCount; ++i) {
+                Service service = services.get(i);
+                // Don't report the UIAutomation (fake service)
+                if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
+                        && (service.mFeedbackType & feedbackType) != 0) {
+                    result.add(service.mAccessibilityServiceInfo);
                 }
             }
         }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 3aba723..20def0c 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -156,7 +156,7 @@
         }
         // Then checks if the session has a response waiting authentication; if so, uses it instead.
         final FillResponse currentResponse = mSession.getCurrentResponse();
-        if (currentResponse.getAuthentication() != null) {
+        if (currentResponse != null && currentResponse.getAuthentication() != null) {
             mListener.onFillReady(currentResponse, this.id, mCurrentValue);
         }
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 413746f..32ff5c5 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -189,7 +189,7 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
-public class BackupManagerService {
+public class BackupManagerService implements IBackupManagerService {
 
     private static final String TAG = "BackupManagerService";
     static final boolean DEBUG = true;
@@ -1728,6 +1728,7 @@
         return false;
     }
 
+    @Override
     public boolean setBackupPassword(String currentPw, String newPw) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupPassword");
@@ -1808,6 +1809,7 @@
         return false;
     }
 
+    @Override
     public boolean hasBackupPassword() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "hasBackupPassword");
@@ -2368,6 +2370,7 @@
 
     // Get the restore-set token for the best-available restore set for this package:
     // the active set if possible, else the ancestral one.  Returns zero if none available.
+    @Override
     public long getAvailableRestoreToken(String packageName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getAvailableRestoreToken");
@@ -2385,10 +2388,12 @@
         return token;
     }
 
+    @Override
     public int requestBackup(String[] packages, IBackupObserver observer, int flags) {
         return requestBackup(packages, observer, null, flags);
     }
 
+    @Override
     public int requestBackup(String[] packages, IBackupObserver observer,
             IBackupManagerMonitor monitor, int flags) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
@@ -2460,6 +2465,7 @@
     }
 
     // Cancel all running backups.
+    @Override
     public void cancelBackups(){
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups");
         if (MORE_DEBUG) {
@@ -9866,6 +9872,7 @@
 
     // ----- IBackupManager binder interface -----
 
+    @Override
     public void dataChanged(final String packageName) {
         final int callingUserHandle = UserHandle.getCallingUserId();
         if (callingUserHandle != UserHandle.USER_SYSTEM) {
@@ -9896,6 +9903,7 @@
     }
 
     // Clear the given package's backup data from the current transport
+    @Override
     public void clearBackupData(String transportName, String packageName) {
         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
         PackageInfo info;
@@ -9953,6 +9961,7 @@
 
     // Run a backup pass immediately for any applications that have declared
     // that they have pending updates.
+    @Override
     public void backupNow() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
 
@@ -9989,6 +9998,7 @@
     //
     // This is the variant used by 'adb backup'; it requires on-screen confirmation
     // by the user because it can be used to offload data over untrusted USB.
+    @Override
     public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
             boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
             boolean compress, boolean doKeyValue, String[] pkgList) {
@@ -10064,6 +10074,7 @@
         }
     }
 
+    @Override
     public void fullTransportBackup(String[] pkgNames) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
                 "fullTransportBackup");
@@ -10113,6 +10124,7 @@
         }
     }
 
+    @Override
     public void adbRestore(ParcelFileDescriptor fd) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore");
 
@@ -10211,6 +10223,7 @@
 
     // Confirm that the previously-requested full backup/restore operation can proceed.  This
     // is used to require a user-facing disclosure about the operation.
+    @Override
     public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
             String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
         if (DEBUG) Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token
@@ -10311,6 +10324,7 @@
     }
 
     // Enable/disable backups
+    @Override
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
@@ -10358,6 +10372,7 @@
     }
 
     // Enable/disable automatic restore of app data at install time
+    @Override
     public void setAutoRestore(boolean doAutoRestore) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setAutoRestore");
@@ -10377,6 +10392,7 @@
     }
 
     // Mark the backup service as having been provisioned
+    @Override
     public void setBackupProvisioned(boolean available) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupProvisioned");
@@ -10386,12 +10402,14 @@
     }
 
     // Report whether the backup mechanism is currently enabled
+    @Override
     public boolean isBackupEnabled() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
         return mEnabled;    // no need to synchronize just to read it
     }
 
     // Report the name of the currently active transport
+    @Override
     public String getCurrentTransport() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getCurrentTransport");
@@ -10401,18 +10419,21 @@
     }
 
     // Report all known, available backup transports
+    @Override
     public String[] listAllTransports() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
 
         return mTransportManager.getBoundTransportNames();
     }
 
+    @Override
     public ComponentName[] listAllTransportComponents() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "listAllTransportComponents");
         return mTransportManager.getAllTransportCompenents();
     }
 
+    @Override
     public String[] getTransportWhitelist() {
         // No permission check, intentionally.
         Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist();
@@ -10426,6 +10447,7 @@
     }
 
     // Select which transport to use for the next backup operation.
+    @Override
     public String selectBackupTransport(String transport) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "selectBackupTransport");
@@ -10443,6 +10465,7 @@
         }
     }
 
+    @Override
     public void selectBackupTransportAsync(final ComponentName transport,
             final ISelectBackupTransportCallback listener) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
@@ -10485,6 +10508,7 @@
     // Supply the configuration Intent for the given transport.  If the name is not one
     // of the available transports, or if the transport does not supply any configuration
     // UI, the method returns null.
+    @Override
     public Intent getConfigurationIntent(String transportName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getConfigurationIntent");
@@ -10510,6 +10534,7 @@
     // summary / destination string, the method can return null.
     //
     // This string is used VERBATIM as the summary text of the relevant Settings item!
+    @Override
     public String getDestinationString(String transportName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getDestinationString");
@@ -10530,6 +10555,7 @@
     }
 
     // Supply the manage-data intent for the given transport.
+    @Override
     public Intent getDataManagementIntent(String transportName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getDataManagementIntent");
@@ -10552,6 +10578,7 @@
 
     // Supply the menu label for affordances that fire the manage-data intent
     // for the given transport.
+    @Override
     public String getDataManagementLabel(String transportName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getDataManagementLabel");
@@ -10573,6 +10600,7 @@
 
     // Callback: a requested backup agent has been instantiated.  This should only
     // be called from the Activity Manager.
+    @Override
     public void agentConnected(String packageName, IBinder agentBinder) {
         synchronized(mAgentConnectLock) {
             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
@@ -10591,6 +10619,7 @@
     // Callback: a backup agent has failed to come up, or has unexpectedly quit.
     // If the agent failed to come up in the first place, the agentBinder argument
     // will be null.  This should only be called from the Activity Manager.
+    @Override
     public void agentDisconnected(String packageName) {
         // TODO: handle backup being interrupted
         synchronized(mAgentConnectLock) {
@@ -10607,6 +10636,7 @@
 
     // An application being installed will need a restore pass, then the Package Manager
     // will need to be told when the restore is finished.
+    @Override
     public void restoreAtInstall(String packageName, int token) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
@@ -10674,6 +10704,7 @@
     }
 
     // Hand off a restore session
+    @Override
     public IRestoreSession beginRestoreSession(String packageName, String transport) {
         if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
                 + " transport=" + transport);
@@ -10737,6 +10768,7 @@
 
     // Note that a currently-active backup agent has notified us that it has
     // completed the given outstanding asynchronous backup/restore operation.
+    @Override
     public void opComplete(int token, long result) {
         if (MORE_DEBUG) {
             Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result);
@@ -10774,6 +10806,7 @@
         }
     }
 
+    @Override
     public boolean isAppEligibleForBackup(String packageName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "isAppEligibleForBackup");
@@ -11138,6 +11171,7 @@
         }
     }
 
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
 
diff --git a/services/backup/java/com/android/server/backup/IBackupManagerService.java b/services/backup/java/com/android/server/backup/IBackupManagerService.java
new file mode 100644
index 0000000..8c6601d
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/IBackupManagerService.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup;
+
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
+import android.app.backup.IFullBackupRestoreObserver;
+import android.app.backup.IRestoreSession;
+import android.app.backup.ISelectBackupTransportCallback;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Interface for BackupManagerService.
+ *
+ * Current and future implementations of BackupManagerService should use this interface, so that
+ * Trampoline is able to switch between them.
+ */
+public interface IBackupManagerService {
+
+  boolean setBackupPassword(String currentPw, String newPw);
+
+  boolean hasBackupPassword();
+
+  // Get the restore-set token for the best-available restore set for this package:
+  // the active set if possible, else the ancestral one.  Returns zero if none available.
+  long getAvailableRestoreToken(String packageName);
+
+  int requestBackup(String[] packages, IBackupObserver observer, int flags);
+
+  int requestBackup(String[] packages, IBackupObserver observer,
+      IBackupManagerMonitor monitor, int flags);
+
+  // Cancel all running backups.
+  void cancelBackups();
+
+  void dataChanged(String packageName);
+
+  // Clear the given package's backup data from the current transport
+  void clearBackupData(String transportName, String packageName);
+
+  // Run a backup pass immediately for any applications that have declared
+  // that they have pending updates.
+  void backupNow();
+
+  // Run a backup pass for the given packages, writing the resulting data stream
+  // to the supplied file descriptor.  This method is synchronous and does not return
+  // to the caller until the backup has been completed.
+  //
+  // This is the variant used by 'adb backup'; it requires on-screen confirmation
+  // by the user because it can be used to offload data over untrusted USB.
+  void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
+      boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
+      boolean compress, boolean doKeyValue, String[] pkgList);
+
+  void fullTransportBackup(String[] pkgNames);
+
+  void adbRestore(ParcelFileDescriptor fd);
+
+  // Confirm that the previously-requested full backup/restore operation can proceed.  This
+  // is used to require a user-facing disclosure about the operation.
+  void acknowledgeAdbBackupOrRestore(int token, boolean allow,
+      String curPassword, String encPpassword, IFullBackupRestoreObserver observer);
+
+  // Enable/disable backups
+  void setBackupEnabled(boolean enable);
+
+  // Enable/disable automatic restore of app data at install time
+  void setAutoRestore(boolean doAutoRestore);
+
+  // Mark the backup service as having been provisioned
+  void setBackupProvisioned(boolean available);
+
+  // Report whether the backup mechanism is currently enabled
+  boolean isBackupEnabled();
+
+  // Report the name of the currently active transport
+  String getCurrentTransport();
+
+  // Report all known, available backup transports
+  String[] listAllTransports();
+
+  ComponentName[] listAllTransportComponents();
+
+  String[] getTransportWhitelist();
+
+  // Select which transport to use for the next backup operation.
+  String selectBackupTransport(String transport);
+
+  void selectBackupTransportAsync(ComponentName transport,
+      ISelectBackupTransportCallback listener);
+
+  // Supply the configuration Intent for the given transport.  If the name is not one
+  // of the available transports, or if the transport does not supply any configuration
+  // UI, the method returns null.
+  Intent getConfigurationIntent(String transportName);
+
+  // Supply the configuration summary string for the given transport.  If the name is
+  // not one of the available transports, or if the transport does not supply any
+  // summary / destination string, the method can return null.
+  //
+  // This string is used VERBATIM as the summary text of the relevant Settings item!
+  String getDestinationString(String transportName);
+
+  // Supply the manage-data intent for the given transport.
+  Intent getDataManagementIntent(String transportName);
+
+  // Supply the menu label for affordances that fire the manage-data intent
+  // for the given transport.
+  String getDataManagementLabel(String transportName);
+
+  // Callback: a requested backup agent has been instantiated.  This should only
+  // be called from the Activity Manager.
+  void agentConnected(String packageName, IBinder agentBinder);
+
+  // Callback: a backup agent has failed to come up, or has unexpectedly quit.
+  // If the agent failed to come up in the first place, the agentBinder argument
+  // will be null.  This should only be called from the Activity Manager.
+  void agentDisconnected(String packageName);
+
+  // An application being installed will need a restore pass, then the Package Manager
+  // will need to be told when the restore is finished.
+  void restoreAtInstall(String packageName, int token);
+
+  // Hand off a restore session
+  IRestoreSession beginRestoreSession(String packageName, String transport);
+
+  // Note that a currently-active backup agent has notified us that it has
+  // completed the given outstanding asynchronous backup/restore operation.
+  void opComplete(int token, long result);
+
+  boolean isAppEligibleForBackup(String packageName);
+
+  void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index a109e631..83d134a 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -139,7 +139,7 @@
     // IBackupManager binder API
     @Override
     public void dataChanged(String packageName) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.dataChanged(packageName);
         }
@@ -148,7 +148,7 @@
     @Override
     public void clearBackupData(String transportName, String packageName)
             throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.clearBackupData(transportName, packageName);
         }
@@ -156,7 +156,7 @@
 
     @Override
     public void agentConnected(String packageName, IBinder agent) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.agentConnected(packageName, agent);
         }
@@ -164,7 +164,7 @@
 
     @Override
     public void agentDisconnected(String packageName) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.agentDisconnected(packageName);
         }
@@ -172,7 +172,7 @@
 
     @Override
     public void restoreAtInstall(String packageName, int token) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.restoreAtInstall(packageName, token);
         }
@@ -180,7 +180,7 @@
 
     @Override
     public void setBackupEnabled(boolean isEnabled) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.setBackupEnabled(isEnabled);
         }
@@ -188,7 +188,7 @@
 
     @Override
     public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.setAutoRestore(doAutoRestore);
         }
@@ -196,7 +196,7 @@
 
     @Override
     public void setBackupProvisioned(boolean isProvisioned) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.setBackupProvisioned(isProvisioned);
         }
@@ -204,25 +204,25 @@
 
     @Override
     public boolean isBackupEnabled() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.isBackupEnabled() : false;
     }
 
     @Override
     public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false;
     }
 
     @Override
     public boolean hasBackupPassword() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.hasBackupPassword() : false;
     }
 
     @Override
     public void backupNow() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.backupNow();
         }
@@ -233,7 +233,7 @@
             boolean includeShared, boolean doWidgets, boolean allApps,
             boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames)
                     throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets,
                     allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
@@ -242,7 +242,7 @@
 
     @Override
     public void fullTransportBackup(String[] packageNames) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.fullTransportBackup(packageNames);
         }
@@ -250,7 +250,7 @@
 
     @Override
     public void adbRestore(ParcelFileDescriptor fd) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.adbRestore(fd);
         }
@@ -260,7 +260,7 @@
     public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
             String encryptionPassword, IFullBackupRestoreObserver observer)
                     throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.acknowledgeAdbBackupOrRestore(token, allow,
                     curPassword, encryptionPassword, observer);
@@ -269,38 +269,38 @@
 
     @Override
     public String getCurrentTransport() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getCurrentTransport() : null;
     }
 
     @Override
     public String[] listAllTransports() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.listAllTransports() : null;
     }
 
     @Override
     public ComponentName[] listAllTransportComponents() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.listAllTransportComponents() : null;
     }
 
     @Override
     public String[] getTransportWhitelist() {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getTransportWhitelist() : null;
     }
 
     @Override
     public String selectBackupTransport(String transport) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.selectBackupTransport(transport) : null;
     }
 
     @Override
     public void selectBackupTransportAsync(ComponentName transport,
             ISelectBackupTransportCallback listener) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.selectBackupTransportAsync(transport, listener);
         }
@@ -308,38 +308,38 @@
 
     @Override
     public Intent getConfigurationIntent(String transport) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getConfigurationIntent(transport) : null;
     }
 
     @Override
     public String getDestinationString(String transport) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getDestinationString(transport) : null;
     }
 
     @Override
     public Intent getDataManagementIntent(String transport) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getDataManagementIntent(transport) : null;
     }
 
     @Override
     public String getDataManagementLabel(String transport) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getDataManagementLabel(transport) : null;
     }
 
     @Override
     public IRestoreSession beginRestoreSession(String packageName, String transportID)
             throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null;
     }
 
     @Override
     public void opComplete(int token, long result) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.opComplete(token, result);
         }
@@ -347,26 +347,26 @@
 
     @Override
     public long getAvailableRestoreToken(String packageName) {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0;
     }
 
     @Override
     public boolean isAppEligibleForBackup(String packageName) {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
     }
 
     @Override
     public int requestBackup(String[] packages, IBackupObserver observer,
             IBackupManagerMonitor monitor, int flags) throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         return (svc != null) ? svc.requestBackup(packages, observer, monitor, flags) : null;
     }
 
     @Override
     public void cancelBackups() throws RemoteException {
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.cancelBackups();
         }
@@ -376,7 +376,7 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        BackupManagerService svc = mService;
+        IBackupManagerService svc = mService;
         if (svc != null) {
             svc.dump(fd, pw, args);
         } else {
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 099f557..8003d21 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -39,8 +39,8 @@
 
 LOCAL_JACK_FLAGS := \
  -D jack.transformations.boost-locked-region-priority=true \
- -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService \
- -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection \
- -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection
+ -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService,com.android.server.wm.WindowHashMap \
+ -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection,com.android.server.wm.WindowManagerService\#boostPriorityForLockedSection \
+ -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection,com.android.server.wm.WindowManagerService\#resetPriorityAfterLockedSection
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4654833..3506745 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,13 +29,6 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.uidRulesToString;
 
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -103,7 +96,6 @@
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
@@ -129,6 +121,7 @@
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.KeepaliveTracker;
@@ -146,6 +139,7 @@
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.LockdownVpnTracker;
+import com.android.server.net.NetworkPolicyManagerInternal;
 
 import com.google.android.collect.Lists;
 
@@ -222,18 +216,6 @@
     private boolean mLockdownEnabled;
     private LockdownVpnTracker mLockdownTracker;
 
-    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
-    private Object mRulesLock = new Object();
-    /** Currently active network rules by UID. */
-    @GuardedBy("mRulesLock")
-    private SparseIntArray mUidRules = new SparseIntArray();
-    /** Set of ifaces that are costly. */
-    @GuardedBy("mRulesLock")
-    private ArraySet<String> mMeteredIfaces = new ArraySet<>();
-    /** Flag indicating if background data is restricted. */
-    @GuardedBy("mRulesLock")
-    private boolean mRestrictBackground;
-
     final private Context mContext;
     private int mNetworkPreference;
     // 0 is full bad, 100 is full good
@@ -247,6 +229,7 @@
     private INetworkManagementService mNetd;
     private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
+    private NetworkPolicyManagerInternal mPolicyManagerInternal;
 
     private String mCurrentTcpBufferSizes;
 
@@ -718,12 +701,15 @@
         mNetd = checkNotNull(netManager, "missing INetworkManagementService");
         mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
         mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
+        mPolicyManagerInternal = checkNotNull(
+                LocalServices.getService(NetworkPolicyManagerInternal.class),
+                "missing NetworkPolicyManagerInternal");
+
         mKeyStore = KeyStore.getInstance();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
 
         try {
-            mPolicyManager.setConnectivityListener(mPolicyListener);
-            mRestrictBackground = mPolicyManager.getRestrictBackground();
+            mPolicyManager.registerListener(mPolicyListener);
         } catch (RemoteException e) {
             // ouch, no rules updates means some processes may never get network
             loge("unable to register INetworkPolicyListener" + e);
@@ -990,51 +976,22 @@
     private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
             boolean ignoreBlocked) {
         // Networks aren't blocked when ignoring blocked status
-        if (ignoreBlocked) return false;
+        if (ignoreBlocked) {
+            return false;
+        }
         // Networks are never blocked for system services
-        if (isSystem(uid)) return false;
-
-        final boolean networkMetered;
-        final int uidRules;
-
+        // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked.
+        if (isSystem(uid)) {
+            return false;
+        }
         synchronized (mVpns) {
             final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
             if (vpn != null && vpn.isBlockingUid(uid)) {
                 return true;
             }
         }
-
         final String iface = (lp == null ? "" : lp.getInterfaceName());
-        synchronized (mRulesLock) {
-            networkMetered = mMeteredIfaces.contains(iface);
-            uidRules = mUidRules.get(uid, RULE_NONE);
-        }
-
-        boolean allowed = true;
-        // Check Data Saver Mode first...
-        if (networkMetered) {
-            if ((uidRules & RULE_REJECT_METERED) != 0) {
-                if (LOGD_RULES) Log.d(TAG, "uid " + uid + " is blacklisted");
-                // Explicitly blacklisted.
-                allowed = false;
-            } else {
-                allowed = !mRestrictBackground
-                      || (uidRules & RULE_ALLOW_METERED) != 0
-                      || (uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0;
-                if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when"
-                        + " mRestrictBackground=" + mRestrictBackground
-                        + ", whitelisted=" + ((uidRules & RULE_ALLOW_METERED) != 0)
-                        + ", tempWhitelist= + ((uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0)"
-                        + ": " + allowed);
-            }
-        }
-        // ...then power restrictions.
-        if (allowed) {
-            allowed = (uidRules & RULE_REJECT_ALL) == 0;
-            if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when"
-                    + " rule is " + uidRulesToString(uidRules) + ": " + allowed);
-        }
-        return !allowed;
+        return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface);
     }
 
     private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) {
@@ -1477,67 +1434,24 @@
         return true;
     }
 
-    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
+    private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
         public void onUidRulesChanged(int uid, int uidRules) {
-            // caller is NPMS, since we only register with them
-            if (LOGD_RULES) {
-                log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
-            }
-
-            synchronized (mRulesLock) {
-                // skip update when we've already applied rules
-                final int oldRules = mUidRules.get(uid, RULE_NONE);
-                if (oldRules == uidRules) return;
-
-                if (uidRules == RULE_NONE) {
-                    mUidRules.delete(uid);
-                } else {
-                    mUidRules.put(uid, uidRules);
-                }
-            }
-
             // TODO: notify UID when it has requested targeted updates
         }
-
         @Override
         public void onMeteredIfacesChanged(String[] meteredIfaces) {
-            // caller is NPMS, since we only register with them
-            if (LOGD_RULES) {
-                log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
-            }
-
-            synchronized (mRulesLock) {
-                mMeteredIfaces.clear();
-                for (String iface : meteredIfaces) {
-                    mMeteredIfaces.add(iface);
-                }
-            }
         }
-
         @Override
         public void onRestrictBackgroundChanged(boolean restrictBackground) {
-            // caller is NPMS, since we only register with them
-            if (LOGD_RULES) {
-                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
-            }
-
-            synchronized (mRulesLock) {
-                mRestrictBackground = restrictBackground;
-            }
-
+            // TODO: relocate this specific callback in Tethering.
             if (restrictBackground) {
                 log("onRestrictBackgroundChanged(true): disabling tethering");
                 mTethering.untetherAll();
             }
         }
-
         @Override
         public void onUidPoliciesChanged(int uid, int uidPolicies) {
-            // caller is NPMS, since we only register with them
-            if (LOGD_RULES) {
-                log("onUidRulesChanged(uid=" + uid + ", uidPolicies=" + uidPolicies + ")");
-            }
         }
     };
 
@@ -1973,33 +1887,6 @@
         pw.decreaseIndent();
         pw.println();
 
-        pw.println("Metered Interfaces:");
-        pw.increaseIndent();
-        for (String value : mMeteredIfaces) {
-            pw.println(value);
-        }
-        pw.decreaseIndent();
-        pw.println();
-
-        pw.print("Restrict background: ");
-        pw.println(mRestrictBackground);
-        pw.println();
-
-        pw.println("Status for known UIDs:");
-        pw.increaseIndent();
-        final int size = mUidRules.size();
-        for (int i = 0; i < size; i++) {
-            final int uid = mUidRules.keyAt(i);
-            pw.print("UID=");
-            pw.print(uid);
-            final int uidRules = mUidRules.get(uid, RULE_NONE);
-            pw.print(" rules=");
-            pw.print(uidRulesToString(uidRules));
-            pw.println();
-        }
-        pw.println();
-        pw.decreaseIndent();
-
         pw.println("Network Requests:");
         pw.increaseIndent();
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -3427,6 +3314,10 @@
         Slog.e(TAG, s);
     }
 
+    private static void loge(String s, Throwable t) {
+        Slog.e(TAG, s, t);
+    }
+
     private static <T> T checkNotNull(T value, String message) {
         if (value == null) {
             throw new NullPointerException(message);
@@ -4176,20 +4067,16 @@
     private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
         final int uid = Binder.getCallingUid();
         if (isSystem(uid)) {
+            // Exemption for system uid.
             return;
         }
-        // if UID is restricted, don't allow them to bring up metered APNs
-        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
-            final int uidRules;
-            synchronized(mRulesLock) {
-                uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
-            }
-            if (mRestrictBackground && (uidRules & RULE_ALLOW_METERED) == 0
-                    && (uidRules & RULE_TEMPORARY_ALLOW_METERED) == 0) {
-                // we could silently fail or we can filter the available nets to only give
-                // them those they have access to.  Chose the more useful option.
-                networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
-            }
+        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+            // Policy already enforced.
+            return;
+        }
+        if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) {
+            // If UID is restricted, don't allow them to bring up metered APNs.
+            networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
         }
     }
 
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 421d5a6..c105b12 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityThread;
 import android.content.Context;
 import android.os.IBinder;
 import android.os.ServiceManager;
@@ -104,6 +105,16 @@
     }
 
     /**
+     * Get the system UI context. This context is to be used for displaying UI. It is themable,
+     * which means resources can be overridden at runtime. Do not use to retrieve properties that
+     * configure the behavior of the device that is not UX related.
+     */
+    public final Context getUiContext() {
+        // This has already been set up by the time any SystemServices are created.
+        return ActivityThread.currentActivityThread().getSystemUiContext();
+    }
+
+    /**
      * Returns true if the system is running in safe mode.
      * TODO: we should define in which phase this becomes valid
      */
diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java
new file mode 100644
index 0000000..17965d0
--- /dev/null
+++ b/services/core/java/com/android/server/ThreadPriorityBooster.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.os.Process;
+
+/**
+ * Utility class to boost threads in sections where important locks are held.
+ */
+public class ThreadPriorityBooster {
+
+    private final int mBoostToPriority;
+    private final int mLockGuardIndex;
+
+    private final ThreadLocal<PriorityState> mThreadState = new ThreadLocal<PriorityState>() {
+        @Override protected PriorityState initialValue() {
+            return new PriorityState();
+        }
+    };
+
+    public ThreadPriorityBooster(int boostToPriority, int lockGuardIndex) {
+        mBoostToPriority = boostToPriority;
+        mLockGuardIndex = lockGuardIndex;
+    }
+
+    public void boost() {
+        final int tid = Process.myTid();
+        final int prevPriority = Process.getThreadPriority(tid);
+        PriorityState state = mThreadState.get();
+        if (state.regionCounter == 0 && prevPriority > mBoostToPriority) {
+            state.prevPriority = prevPriority;
+            Process.setThreadPriority(tid, mBoostToPriority);
+        }
+        state.regionCounter++;
+        if (LockGuard.ENABLED) {
+            LockGuard.guard(mLockGuardIndex);
+        }
+    }
+
+    public void reset() {
+        PriorityState state = mThreadState.get();
+        state.regionCounter--;
+        if (state.regionCounter == 0 && state.prevPriority > mBoostToPriority) {
+            Process.setThreadPriority(Process.myTid(), state.prevPriority);
+        }
+    }
+
+    private static class PriorityState {
+
+        /**
+         * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
+         * the current thread is currently in. When it drops down to zero, we will no longer boost
+         * the thread's priority.
+         */
+        int regionCounter;
+
+        /**
+         * The thread's previous priority before boosting.
+         */
+        int prevPriority;
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d996ee2..e560d32 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -123,7 +123,6 @@
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -191,17 +190,14 @@
     }
 
     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
-    private final AtomicInteger mNotificationIds =
-            new AtomicInteger(SystemMessage.ACCOUNT_MANAGER_BASE);
 
     static class UserAccounts {
         private final int userId;
         final AccountsDb accountsDb;
-        private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
-                credentialsPermissionNotificationIds =
-                new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
-        private final HashMap<Account, Integer> signinRequiredNotificationIds =
-                new HashMap<Account, Integer>();
+        private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId>
+                credentialsPermissionNotificationIds = new HashMap<>();
+        private final HashMap<Account, NotificationId> signinRequiredNotificationIds
+                = new HashMap<>();
         final Object cacheLock = new Object();
         final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock
         /** protected by the {@link #cacheLock} */
@@ -1863,12 +1859,12 @@
          */
         cancelNotification(
                 getSigninRequiredNotificationId(accounts, accountToRename),
-                 new UserHandle(accounts.userId));
+                new UserHandle(accounts.userId));
         synchronized(accounts.credentialsPermissionNotificationIds) {
             for (Pair<Pair<Account, String>, Integer> pair:
                     accounts.credentialsPermissionNotificationIds.keySet()) {
                 if (accountToRename.equals(pair.first.first)) {
-                    int id = accounts.credentialsPermissionNotificationIds.get(pair);
+                    NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
                     cancelNotification(id, new UserHandle(accounts.userId));
                 }
             }
@@ -2021,7 +2017,7 @@
             for (Pair<Pair<Account, String>, Integer> pair:
                 accounts.credentialsPermissionNotificationIds.keySet()) {
                 if (account.equals(pair.first.first)) {
-                    int id = accounts.credentialsPermissionNotificationIds.get(pair);
+                    NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair);
                     cancelNotification(id, user);
                 }
             }
@@ -2912,8 +2908,8 @@
             // the intent from a non-Activity context. This is the default behavior.
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         }
-        intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
-                authTokenType, uid) + (packageName != null ? packageName : "")));
+        intent.addCategory(getCredentialPermissionNotificationId(account,
+                authTokenType, uid).mTag + (packageName != null ? packageName : ""));
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
@@ -2922,33 +2918,39 @@
         return intent;
     }
 
-    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
-            int uid) {
-        Integer id;
+    private NotificationId getCredentialPermissionNotificationId(Account account,
+            String authTokenType, int uid) {
+        NotificationId nId;
         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.credentialsPermissionNotificationIds) {
             final Pair<Pair<Account, String>, Integer> key =
                     new Pair<Pair<Account, String>, Integer>(
                             new Pair<Account, String>(account, authTokenType), uid);
-            id = accounts.credentialsPermissionNotificationIds.get(key);
-            if (id == null) {
-                id = mNotificationIds.incrementAndGet();
-                accounts.credentialsPermissionNotificationIds.put(key, id);
+            nId = accounts.credentialsPermissionNotificationIds.get(key);
+            if (nId == null) {
+                String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION
+                        + ":" + account.hashCode() + ":" + authTokenType.hashCode();
+                int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION;
+                nId = new NotificationId(tag, id);
+                accounts.credentialsPermissionNotificationIds.put(key, nId);
             }
         }
-        return id;
+        return nId;
     }
 
-    private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
-        Integer id;
+    private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
+        NotificationId nId;
         synchronized (accounts.signinRequiredNotificationIds) {
-            id = accounts.signinRequiredNotificationIds.get(account);
-            if (id == null) {
-                id = mNotificationIds.incrementAndGet();
-                accounts.signinRequiredNotificationIds.put(account, id);
+            nId = accounts.signinRequiredNotificationIds.get(account);
+            if (nId == null) {
+                String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN
+                        + ":" + account.hashCode();
+                int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN;
+                nId = new NotificationId(tag, id);
+                accounts.signinRequiredNotificationIds.put(account, nId);
             }
         }
-        return id;
+        return nId;
     }
 
     @Override
@@ -4931,8 +4933,8 @@
                 createNoCredentialsPermissionNotification(account, intent, packageName, userId);
             } else {
                 Context contextForUser = getContextForUser(new UserHandle(userId));
-                final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
-                intent.addCategory(String.valueOf(notificationId));
+                final NotificationId id = getSigninRequiredNotificationId(accounts, account);
+                intent.addCategory(id.mTag);
 
                 final String notificationTitleFormat =
                         contextForUser.getText(R.string.notification_title).toString();
@@ -4948,21 +4950,21 @@
                                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
                                 null, new UserHandle(userId)))
                         .build();
-                installNotification(notificationId, n, packageName, userId);
+                installNotification(id, n, packageName, userId);
             }
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
-    private void installNotification(int notificationId, final Notification notification,
+    private void installNotification(NotificationId id, final Notification notification,
             String packageName, int userId) {
         final long token = clearCallingIdentity();
         try {
             INotificationManager notificationManager = mInjector.getNotificationManager();
             try {
-                notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
-                        notificationId, notification, new int[1], userId);
+                notificationManager.enqueueNotificationWithTag(packageName, packageName,
+                        id.mTag, id.mId, notification, new int[1], userId);
             } catch (RemoteException e) {
                 /* ignore - local call */
             }
@@ -4971,15 +4973,15 @@
         }
     }
 
-    private void cancelNotification(int id, UserHandle user) {
+    private void cancelNotification(NotificationId id, UserHandle user) {
         cancelNotification(id, mContext.getPackageName(), user);
     }
 
-    private void cancelNotification(int id, String packageName, UserHandle user) {
+    private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
         long identityToken = clearCallingIdentity();
         try {
             INotificationManager service = mInjector.getNotificationManager();
-            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
+            service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier());
         } catch (RemoteException e) {
             /* ignore - local call */
         } finally {
@@ -5893,4 +5895,14 @@
             return NotificationManager.getService();
         }
     }
+
+    private class NotificationId {
+        final String mTag;
+        private final int mId;
+
+        NotificationId(String tag, int type) {
+            mTag = tag;
+            mId = type;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9ad945f..4cbfb27 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1140,7 +1140,7 @@
                 // Service is already running, so we can immediately
                 // publish the connection.
                 try {
-                    c.conn.connected(s.name, b.intent.binder);
+                    c.conn.connected(s.name, b.intent.binder, false);
                 } catch (Exception e) {
                     Slog.w(TAG, "Failure sending service " + s.shortName
                             + " to connection " + c.conn.asBinder()
@@ -1194,7 +1194,7 @@
                             }
                             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                             try {
-                                c.conn.connected(r.name, service);
+                                c.conn.connected(r.name, service, false);
                             } catch (Exception e) {
                                 Slog.w(TAG, "Failure sending service " + r.name +
                                       " to connection " + c.conn.asBinder() +
@@ -2081,7 +2081,7 @@
                 // being brought down.  Mark it as dead.
                 cr.serviceDead = true;
                 try {
-                    cr.conn.connected(r.name, null);
+                    cr.conn.connected(r.name, null, true);
                 } catch (Exception e) {
                     Slog.w(TAG, "Failure disconnecting service " + r.name +
                           " to connection " + c.get(i).conn.asBinder() +
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7618144..19fc2b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,12 +17,12 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
 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;
@@ -42,13 +42,49 @@
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
 import static android.os.Build.VERSION_CODES.N;
+import static android.os.Process.BLUETOOTH_UID;
+import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.FIRST_ISOLATED_UID;
+import static android.os.Process.LAST_ISOLATED_UID;
+import static android.os.Process.NFC_UID;
+import static android.os.Process.PHONE_UID;
 import static android.os.Process.PROC_CHAR;
 import static android.os.Process.PROC_OUT_LONG;
 import static android.os.Process.PROC_PARENS;
 import static android.os.Process.PROC_SPACE_TERM;
-import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
-import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
+import static android.os.Process.ProcessStartResult;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SCHED_FIFO;
+import static android.os.Process.SCHED_OTHER;
+import static android.os.Process.SCHED_RESET_ON_FORK;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SIGNAL_QUIT;
+import static android.os.Process.SIGNAL_USR1;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
+import static android.os.Process.THREAD_GROUP_DEFAULT;
+import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.os.Process.getFreeMemory;
+import static android.os.Process.getThreadPriority;
+import static android.os.Process.getTotalMemory;
+import static android.os.Process.isThreadInProcess;
+import static android.os.Process.killProcess;
+import static android.os.Process.killProcessQuiet;
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
+import static android.os.Process.readProcFile;
+import static android.os.Process.removeAllProcessGroups;
+import static android.os.Process.sendSignal;
+import static android.os.Process.setProcessGroup;
+import static android.os.Process.setThreadPriority;
+import static android.os.Process.setThreadScheduler;
+import static android.os.Process.startWebView;
+import static android.os.Process.zygoteProcess;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -323,7 +359,6 @@
 import android.view.View;
 import android.view.WindowManager;
 
-import com.android.internal.notification.SystemNotificationChannels;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -341,6 +376,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.IResultReceiver;
@@ -367,6 +403,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
+import com.android.server.ThreadPriorityBooster;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.firewall.IntentFirewall;
@@ -409,7 +446,6 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.VMRuntime;
-
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -547,7 +583,7 @@
     // Maximum number of persisted Uri grants a package is allowed
     static final int MAX_PERSISTED_URI_GRANTS = 128;
 
-    static final int MY_PID = Process.myPid();
+    static final int MY_PID = myPid();
 
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
@@ -680,13 +716,13 @@
                     if (mTopAppVrThreadTid > 0) {
                         // Ensure that when entering persistent VR mode the last top-app loses
                         // SCHED_FIFO.
-                        Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0);
+                        setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
                         mTopAppVrThreadTid = 0;
                     }
                 } else if (mPersistentVrThreadTid > 0) {
                     // Ensure that when leaving persistent VR mode we reschedule the high priority
                     // persistent thread.
-                    Process.setThreadScheduler(mPersistentVrThreadTid, Process.SCHED_OTHER, 0);
+                    setThreadScheduler(mPersistentVrThreadTid, SCHED_OTHER, 0);
                     mPersistentVrThreadTid = 0;
                 }
             }
@@ -773,42 +809,15 @@
                 && !mKeyguardController.isKeyguardShowing();
     }
 
-    private static final class PriorityState {
-        // Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
-        // the current thread is currently in. When it drops down to zero, we will no longer boost
-        // the thread's priority.
-        private int regionCounter = 0;
-
-        // The thread's previous priority before boosting.
-        private int prevPriority = Integer.MIN_VALUE;
-    }
-
-    static ThreadLocal<PriorityState> sThreadPriorityState = new ThreadLocal<PriorityState>() {
-        @Override protected PriorityState initialValue() {
-            return new PriorityState();
-        }
-    };
+    private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster(
+            THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_ACTIVITY);
 
     static void boostPriorityForLockedSection() {
-        int tid = Process.myTid();
-        int prevPriority = Process.getThreadPriority(tid);
-        PriorityState state = sThreadPriorityState.get();
-        if (state.regionCounter == 0 && prevPriority > -2) {
-            state.prevPriority = prevPriority;
-            Process.setThreadPriority(tid, -2);
-        }
-        state.regionCounter++;
-        if (LockGuard.ENABLED) {
-            LockGuard.guard(LockGuard.INDEX_ACTIVITY);
-        }
+        sThreadPriorityBooster.boost();
     }
 
     static void resetPriorityAfterLockedSection() {
-        PriorityState state = sThreadPriorityState.get();
-        state.regionCounter--;
-        if (state.regionCounter == 0 && state.prevPriority > -2) {
-            Process.setThreadPriority(Process.myTid(), state.prevPriority);
-        }
+        sThreadPriorityBooster.reset();
     }
 
     public class PendingAssistExtras extends Binder implements Runnable {
@@ -889,7 +898,7 @@
      * Non-persistent app uid whitelist for background restrictions
      */
     int[] mBackgroundUidWhitelist = new int[] {
-            Process.BLUETOOTH_UID
+            BLUETOOTH_UID
     };
 
     /**
@@ -1350,7 +1359,13 @@
     @GuardedBy("this") boolean mLaunchWarningShown = false;
     @GuardedBy("this") boolean mCheckedForSetup = false;
 
-    Context mContext;
+    final Context mContext;
+
+    /**
+     * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
+     * change at runtime. Use mContext for non-UI purposes.
+     */
+    final Context mUiContext;
 
     /**
      * The time at which we will allow normal application switches again,
@@ -1852,7 +1867,7 @@
             } break;
             case SHOW_FACTORY_ERROR_UI_MSG: {
                 Dialog d = new FactoryErrorDialog(
-                    mContext, msg.getData().getCharSequence("msg"));
+                        mUiContext, msg.getData().getCharSequence("msg"));
                 d.show();
                 ensureBootCompleted();
             } break;
@@ -1863,7 +1878,7 @@
                         if (!app.waitedForDebugger) {
                             Dialog d = new AppWaitingForDebuggerDialog(
                                     ActivityManagerService.this,
-                                    mContext, app);
+                                    mUiContext, app);
                             app.waitDialog = d;
                             app.waitedForDebugger = true;
                             d.show();
@@ -1878,24 +1893,24 @@
             } break;
             case SHOW_UID_ERROR_UI_MSG: {
                 if (mShowDialogs) {
-                    AlertDialog d = new BaseErrorDialog(mContext);
+                    AlertDialog d = new BaseErrorDialog(mUiContext);
                     d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
                     d.setCancelable(false);
-                    d.setTitle(mContext.getText(R.string.android_system_label));
-                    d.setMessage(mContext.getText(R.string.system_error_wipe_data));
-                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                    d.setTitle(mUiContext.getText(R.string.android_system_label));
+                    d.setMessage(mUiContext.getText(R.string.system_error_wipe_data));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),
                             obtainMessage(DISMISS_DIALOG_UI_MSG, d));
                     d.show();
                 }
             } break;
             case SHOW_FINGERPRINT_ERROR_UI_MSG: {
                 if (mShowDialogs) {
-                    AlertDialog d = new BaseErrorDialog(mContext);
+                    AlertDialog d = new BaseErrorDialog(mUiContext);
                     d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
                     d.setCancelable(false);
-                    d.setTitle(mContext.getText(R.string.android_system_label));
-                    d.setMessage(mContext.getText(R.string.system_error_manufacturer));
-                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                    d.setTitle(mUiContext.getText(R.string.android_system_label));
+                    d.setMessage(mUiContext.getText(R.string.system_error_manufacturer));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),
                             obtainMessage(DISMISS_DIALOG_UI_MSG, d));
                     d.show();
                 }
@@ -1919,7 +1934,7 @@
                             if (mode == ActivityManager.COMPAT_MODE_DISABLED
                                     || mode == ActivityManager.COMPAT_MODE_ENABLED) {
                                 mCompatModeDialog = new CompatModeDialog(
-                                        ActivityManagerService.this, mContext,
+                                        ActivityManagerService.this, mUiContext,
                                         ar.info.applicationInfo);
                                 mCompatModeDialog.show();
                             }
@@ -1939,7 +1954,7 @@
                             ar.packageName)) {
                         // TODO(multi-display): Show dialog on appropriate display.
                         mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog(
-                                ActivityManagerService.this, mContext, ar.info.applicationInfo);
+                                ActivityManagerService.this, mUiContext, ar.info.applicationInfo);
                         mUnsupportedDisplaySizeDialog.show();
                     }
                 }
@@ -2461,12 +2476,12 @@
                                 if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                                     try {
                                         if (mVrState == VR_MODE) {
-                                            Process.setThreadScheduler(proc.vrThreadTid,
-                                                Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                            setThreadScheduler(proc.vrThreadTid,
+                                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                             mTopAppVrThreadTid = proc.vrThreadTid;
                                         } else {
-                                            Process.setThreadScheduler(proc.vrThreadTid,
-                                                Process.SCHED_OTHER, 0);
+                                            setThreadScheduler(proc.vrThreadTid,
+                                                SCHED_OTHER, 0);
                                             mTopAppVrThreadTid = 0;
                                         }
                                     } catch (IllegalArgumentException e) {
@@ -2523,7 +2538,7 @@
                     final List<ProcessCpuTracker.Stats> stats;
                     synchronized (mProcessCpuTracker) {
                         stats = mProcessCpuTracker.getStats( (st)-> {
-                            return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
+                            return st.vsize > 0 && st.uid < FIRST_APPLICATION_UID;
                         });
                     }
                     final int N = stats.size();
@@ -2731,6 +2746,7 @@
     public ActivityManagerService(Injector injector) {
         mInjector = injector;
         mContext = mInjector.getContext();
+        mUiContext = null;
         GL_ES_VERSION = 0;
         mActivityStarter = null;
         mAppErrors = null;
@@ -2762,8 +2778,10 @@
         LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
         mInjector = new Injector();
         mContext = systemContext;
+
         mFactoryTest = FactoryTest.getMode();
         mSystemThread = ActivityThread.currentActivityThread();
+        mUiContext = mSystemThread.getSystemUiContext();
 
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
 
@@ -2771,7 +2789,7 @@
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
         mHandlerThread = new ServiceThread(TAG,
-                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+                THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new MainHandler(mHandlerThread.getLooper());
         mUiHandler = mInjector.getUiHandler(this);
@@ -2792,7 +2810,7 @@
         /* static; one-time init here */
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
-                    android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+                    THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
             sKillThread.start();
             sKillHandler = new KillHandler(sKillThread.getLooper());
         }
@@ -2806,7 +2824,7 @@
 
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
-        mAppErrors = new AppErrors(mContext, this);
+        mAppErrors = new AppErrors(mUiContext, this);
 
         // TODO: Move creation of battery stats service outside of activity manager service.
         File dataDir = Environment.getDataDirectory();
@@ -2849,7 +2867,7 @@
         mTempConfig.setToDefaults();
         mTempConfig.setLocales(LocaleList.getDefault());
         mConfigurationSeq = mTempConfig.seq = 1;
-        mStackSupervisor = new ActivityStackSupervisor(this);
+        mStackSupervisor = createStackSupervisor();
         mStackSupervisor.onConfigurationChanged(mTempConfig);
         mKeyguardController = mStackSupervisor.mKeyguardController;
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
@@ -2897,6 +2915,10 @@
         Watchdog.getInstance().addThread(mHandler);
     }
 
+    protected ActivityStackSupervisor createStackSupervisor() {
+        return new ActivityStackSupervisor(this, mHandler.getLooper());
+    }
+
     public void setSystemServiceManager(SystemServiceManager mgr) {
         mSystemServiceManager = mgr;
     }
@@ -2906,7 +2928,7 @@
     }
 
     private void start() {
-        Process.removeAllProcessGroups();
+        removeAllProcessGroups();
         mProcessCpuThread.start();
 
         mBatteryStatsService.publish(mContext);
@@ -3114,7 +3136,7 @@
         synchronized (this) {
             broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
                     AppOpsManager.OP_NONE, null, false, false,
-                    -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                    -1, SYSTEM_UID, UserHandle.USER_ALL);
         }
     }
 
@@ -3151,7 +3173,8 @@
      * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
      */
     void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
-        if (r.task.isApplicationTask()) {
+        final TaskRecord task = r.getTask();
+        if (task.isApplicationTask()) {
             if (mCurAppTimeTracker != r.appTimeTracker) {
                 // We are switching app tracking.  Complete the current one.
                 if (mCurAppTimeTracker != null) {
@@ -3174,17 +3197,18 @@
         // TODO: VI Maybe r.task.voiceInteractor || r.voiceInteractor != null
         // TODO: Probably not, because we don't want to resume voice on switching
         // back to this activity
-        if (r.task.voiceInteractor != null) {
-            startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
+        if (task.voiceInteractor != null) {
+            startRunningVoiceLocked(task.voiceSession, r.info.applicationInfo.uid);
         } else {
             finishRunningVoiceLocked();
 
             if (mLastResumedActivity != null) {
                 final IVoiceInteractionSession session;
 
-                if (mLastResumedActivity.task != null
-                        && mLastResumedActivity.task.voiceSession != null) {
-                    session = mLastResumedActivity.task.voiceSession;
+                final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTask();
+                if (lastResumedActivityTask != null
+                        && lastResumedActivityTask.voiceSession != null) {
+                    session = lastResumedActivityTask.voiceSession;
                 } else {
                     session = mLastResumedActivity.voiceSession;
                 }
@@ -3317,7 +3341,7 @@
     final void showAskCompatModeDialogLocked(ActivityRecord r) {
         Message msg = Message.obtain();
         msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
-        msg.obj = r.task.askedCompatMode ? null : r;
+        msg.obj = r.getTask().askedCompatMode ? null : r;
         mUiHandler.sendMessage(msg);
     }
 
@@ -3384,7 +3408,7 @@
         if (lrui >= 0) {
             if (!app.killed) {
                 Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
-                Process.killProcessQuiet(app.pid);
+                killProcessQuiet(app.pid);
                 killProcessGroup(app.uid, app.pid);
             }
             if (lrui <= mLruProcessActivityStart) {
@@ -3593,7 +3617,7 @@
     }
 
     final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
-        if (uid == Process.SYSTEM_UID) {
+        if (uid == SYSTEM_UID) {
             // The system gets to run in any process.  If there are multiple
             // processes with the same uid, just pick the first (this
             // should never happen).
@@ -3659,7 +3683,7 @@
             // closest thing to a parent's uid is SYSTEM_UID.
             // The only important thing here is to keep AI.uid != PR.uid, in order to trigger
             // the |isolated| logic in the ProcessRecord constructor.
-            info.uid = Process.SYSTEM_UID;
+            info.uid = SYSTEM_UID;
             info.processName = processName;
             info.className = entryPoint;
             info.packageName = "android";
@@ -3954,9 +3978,9 @@
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                     app.processName);
             checkTime(startTime, "startProcess: asking zygote to start proc");
-            Process.ProcessStartResult startResult;
+            ProcessStartResult startResult;
             if (hostingType.equals("webview_service")) {
-                startResult = Process.startWebView(entryPoint,
+                startResult = startWebView(entryPoint,
                         app.processName, uid, uid, gids, debugFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, entryPointArgs);
@@ -4193,7 +4217,7 @@
     }
 
     void enforceShellRestriction(String restriction, int userHandle) {
-        if (Binder.getCallingUid() == Process.SHELL_UID) {
+        if (Binder.getCallingUid() == SHELL_UID) {
             if (userHandle < 0 || mUserController.hasUserRestriction(restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
@@ -4559,7 +4583,7 @@
             if (sourceRecord.app == null) {
                 throw new SecurityException("Called without a process attached to activity");
             }
-            if (UserHandle.getAppId(sourceRecord.app.uid) != Process.SYSTEM_UID) {
+            if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) {
                 // This is still okay, as long as this activity is running under the
                 // uid of the original calling activity.
                 if (sourceRecord.app.uid != sourceRecord.launchedFromUid) {
@@ -4723,7 +4747,7 @@
             if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
                 throw new SecurityException("Only focused activity can call startVoiceInteraction");
             }
-            if (mRunningVoice != null || activity.task.voiceSession != null
+            if (mRunningVoice != null || activity.getTask().voiceSession != null
                     || activity.voiceSession != null) {
                 Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
                 return;
@@ -5033,7 +5057,7 @@
                 return true;
             }
             // Keep track of the root activity of the task before we finish it
-            TaskRecord tr = r.task;
+            TaskRecord tr = r.getTask();
             ActivityRecord rootR = tr.getRootActivity();
             if (rootR == null) {
                 Slog.w(TAG, "Finishing task with all activities already finished");
@@ -5170,7 +5194,7 @@
 
                 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
                 // can finish.
-                final TaskRecord task = r.task;
+                final TaskRecord task = r.getTask();
                 if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
                         mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
                     mStackSupervisor.showLockTaskToast();
@@ -5411,7 +5435,7 @@
 
         if (!app.killed) {
             if (!fromBinderDied) {
-                Process.killProcessQuiet(pid);
+                killProcessQuiet(pid);
             }
             killProcessGroup(app.uid, pid);
             app.killed = true;
@@ -5506,7 +5530,7 @@
         }
 
         public void dumpWithTimeout(int pid) {
-            Process.sendSignal(pid, Process.SIGNAL_QUIT);
+            sendSignal(pid, SIGNAL_QUIT);
             synchronized (this) {
                 try {
                     wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed.
@@ -5761,7 +5785,7 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                     intent.putExtra(Intent.EXTRA_UID, pkgUidF);
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF));
-                    broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
+                    broadcastIntentInPackage("android", SYSTEM_UID, intent,
                             null, null, 0, null, null, null, null, false, false, userIdF);
 
                     if (observer != null) {
@@ -5979,7 +6003,7 @@
     public void addPackageDependency(String packageName) {
         synchronized (this) {
             int callingPid = Binder.getCallingPid();
-            if (callingPid == Process.myPid()) {
+            if (callingPid == myPid()) {
                 //  Yeah, um, no.
                 return;
             }
@@ -6011,7 +6035,7 @@
         }
         int callerUid = Binder.getCallingUid();
         // Only the system server can kill an application
-        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callerUid) == SYSTEM_UID) {
             // Post an aysnc message to kill the application
             Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
             msg.arg1 = appId;
@@ -6038,7 +6062,7 @@
             synchronized (this) {
                 // Only allow this from foreground processes, so that background
                 // applications can't abuse it to prevent system UI from being shown.
-                if (uid >= Process.FIRST_APPLICATION_UID) {
+                if (uid >= FIRST_APPLICATION_UID) {
                     ProcessRecord proc;
                     synchronized (mPidsSelfLocked) {
                         proc = mPidsSelfLocked.get(pid);
@@ -6069,7 +6093,7 @@
 
         broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
                 AppOpsManager.OP_NONE, null, false, false,
-                -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                -1, SYSTEM_UID, UserHandle.USER_ALL);
     }
 
     @Override
@@ -6135,7 +6159,7 @@
 
         int callerUid = Binder.getCallingUid();
         // Only the system server can kill an application
-        if (callerUid == Process.SYSTEM_UID) {
+        if (callerUid == SYSTEM_UID) {
             synchronized (this) {
                 ProcessRecord app = getProcessRecordLocked(processName, uid, true);
                 if (app != null && app.thread != null) {
@@ -6171,7 +6195,7 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
+                null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
     }
 
 
@@ -6688,7 +6712,7 @@
                     + " (IApplicationThread " + thread + "); dropping process");
             EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
             if (pid > 0 && pid != MY_PID) {
-                Process.killProcessQuiet(pid);
+                killProcessQuiet(pid);
                 //TODO: killProcessGroup(app.info.uid, pid);
             } else {
                 try {
@@ -6796,7 +6820,7 @@
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
             if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
                         && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
                                 || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                                 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
@@ -7019,7 +7043,7 @@
 
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (Binder.getCallingUid() != Process.myUid()) {
+        if (Binder.getCallingUid() != myUid()) {
             throw new SecurityException();
         }
         mWindowManager.showBootMessage(msg, always);
@@ -7056,7 +7080,7 @@
 
         ArraySet<String> completedIsas = new ArraySet<String>();
         for (String abi : Build.SUPPORTED_ABIS) {
-            Process.zygoteProcess.establishZygoteConnectionForAbi(abi);
+            zygoteProcess.establishZygoteConnectionForAbi(abi);
             final String instructionSet = VMRuntime.getInstructionSet(abi);
             if (!completedIsas.contains(instructionSet)) {
                 try {
@@ -7397,7 +7421,7 @@
                 userId = UserHandle.USER_CURRENT;
             }
             try {
-                if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+                if (callingUid != 0 && callingUid != SYSTEM_UID) {
                     final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
                             MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid));
                     if (!UserHandle.isSameApp(callingUid, uid)) {
@@ -7834,7 +7858,7 @@
                     return false;
                 }
                 // An activity is consider to be in multi-window mode if its task isn't fullscreen.
-                return !r.task.mFullscreen;
+                return !r.getTask().mFullscreen;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -8664,7 +8688,7 @@
         // Third...  does the caller itself have permission to access
         // this uri?
         final int callingAppId = UserHandle.getAppId(callingUid);
-        if ((callingAppId == Process.SYSTEM_UID) || (callingAppId == Process.ROOT_UID)) {
+        if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
             if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
                 // Exempted authority for cropping user photos in Settings app
             } else {
@@ -9150,7 +9174,7 @@
                 throw new IllegalArgumentException("Unknown owner: " + token);
             }
             if (fromUid != Binder.getCallingUid()) {
-                if (Binder.getCallingUid() != Process.myUid()) {
+                if (Binder.getCallingUid() != myUid()) {
                     // Only system code can grant URI permissions on behalf
                     // of other users.
                     throw new SecurityException("nice try");
@@ -9534,8 +9558,8 @@
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
         final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
         final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ);
-        outInfo.availMem = Process.getFreeMemory();
-        outInfo.totalMem = Process.getTotalMemory();
+        outInfo.availMem = getFreeMemory();
+        outInfo.totalMem = getTotalMemory();
         outInfo.threshold = homeAppMem;
         outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
         outInfo.hiddenAppThreshold = cachedAppMem;
@@ -9927,8 +9951,9 @@
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
                 r.setTaskDescription(td);
-                r.task.updateTaskDescription();
-                mTaskChangeNotificationController.notifyTaskDescriptionChanged(r.task.taskId, td);
+                final TaskRecord task = r.getTask();
+                task.updateTaskDescription();
+                mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.taskId, td);
             }
         }
     }
@@ -10378,8 +10403,8 @@
                 }
 
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
-                r.task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT,
-                        ANIMATE, !DEFER_RESUME, "exitFreeformMode");
+                r.getTask().reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
+                        REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode");
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -10677,7 +10702,7 @@
     @Override
     public void updateDeviceOwner(String packageName) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
             throw new SecurityException("updateDeviceOwner called from non-system process");
         }
         synchronized (this) {
@@ -10688,7 +10713,7 @@
     @Override
     public void updateLockTaskPackages(int userId, String[] packages) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
             enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
                     "updateLockTaskPackages()");
         }
@@ -10711,7 +10736,7 @@
         // is initiated by system after the pinning request was shown and locked mode is initiated
         // by an authorized app directly
         final int callingUid = Binder.getCallingUid();
-        boolean isSystemInitiated = callingUid == Process.SYSTEM_UID;
+        boolean isSystemInitiated = callingUid == SYSTEM_UID;
         long ident = Binder.clearCallingIdentity();
         try {
             if (!isSystemInitiated) {
@@ -10760,7 +10785,7 @@
             if (r == null) {
                 return;
             }
-            final TaskRecord task = r.task;
+            final TaskRecord task = r.getTask();
             if (task != null) {
                 startLockTaskModeLocked(task);
             }
@@ -10859,7 +10884,7 @@
             if (r == null) {
                 return;
             }
-            mStackSupervisor.showLockTaskEscapeMessageLocked(r.task);
+            mStackSupervisor.showLockTaskEscapeMessageLocked(r.getTask());
         }
     }
 
@@ -11190,7 +11215,7 @@
             proc.procStatFile = "/proc/" + proc.pid + "/stat";
         }
         mProcessStateStatsLongs[0] = 0;
-        if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+        if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
                 mProcessStateStatsLongs, null)) {
             if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
             return false;
@@ -11892,7 +11917,7 @@
     public final void installSystemProviders() {
         List<ProviderInfo> providers;
         synchronized (this) {
-            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
+            ProcessRecord app = mProcessNames.get("system", SYSTEM_UID);
             providers = generateApplicationProvidersLocked(app);
             if (providers != null) {
                 for (int i=providers.size()-1; i>=0; i--) {
@@ -12065,11 +12090,11 @@
         int uid = info.uid;
         if (isolated) {
             if (isolatedUid == 0) {
-                int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+                int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
                 while (true) {
-                    if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
-                            || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
-                        mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+                    if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
+                            || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
+                        mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
                     }
                     uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
                     mNextIsolatedProcessUid++;
@@ -13121,9 +13146,10 @@
                 if (r == null) {
                     return false;
                 }
-                int index = r.task.mActivities.lastIndexOf(r);
+                final TaskRecord task = r.getTask();
+                int index = task.mActivities.lastIndexOf(r);
                 if (index > 0) {
-                    ActivityRecord under = r.task.mActivities.get(index - 1);
+                    ActivityRecord under = task.mActivities.get(index - 1);
                     under.returningOptions = ActivityOptions.fromBundle(options);
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(false);
@@ -13257,7 +13283,7 @@
         synchronized (this) {
             // Disable any existing VR thread.
             if (mTopAppVrThreadTid > 0) {
-                Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0);
+                setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
                 mTopAppVrThreadTid = 0;
             }
 
@@ -13281,15 +13307,15 @@
      */
     private int updateVrThreadLocked(ProcessRecord proc, int lastTid, int pid, int tid) {
         // ensure the tid belongs to the process
-        if (!Process.isThreadInProcess(pid, tid)) {
+        if (!isThreadInProcess(pid, tid)) {
             throw new IllegalArgumentException("VR thread does not belong to process");
         }
 
         // reset existing VR thread to CFS if this thread still exists and belongs to
         // the calling process
-        if (lastTid != 0 && Process.isThreadInProcess(pid, lastTid)) {
+        if (lastTid != 0 && isThreadInProcess(pid, lastTid)) {
             try {
-                Process.setThreadScheduler(lastTid, Process.SCHED_OTHER, 0);
+                setThreadScheduler(lastTid, SCHED_OTHER, 0);
             } catch (IllegalArgumentException e) {
                 // Ignore this.  Only occurs in race condition where previous VR thread
                 // was destroyed during this method call.
@@ -13300,8 +13326,8 @@
         try {
             if ((proc == null || proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP)
                     && tid > 0) {
-                Process.setThreadScheduler(tid,
-                    Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                setThreadScheduler(tid,
+                    SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
             }
             return tid;
         } catch (IllegalArgumentException e) {
@@ -13320,7 +13346,7 @@
                 proc = mPidsSelfLocked.get(pid);
                 if (proc != null && proc.renderThreadTid == 0 && tid > 0) {
                     // ensure the tid belongs to the process
-                    if (!Process.isThreadInProcess(pid, tid)) {
+                    if (!isThreadInProcess(pid, tid)) {
                         throw new IllegalArgumentException(
                             "Render thread does not belong to process");
                     }
@@ -13332,10 +13358,10 @@
                     if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");
                         if (mUseFifoUiScheduling) {
-                            Process.setThreadScheduler(proc.renderThreadTid,
-                                Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                            setThreadScheduler(proc.renderThreadTid,
+                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                         } else {
-                            Process.setThreadPriority(proc.renderThreadTid, -10);
+                            setThreadPriority(proc.renderThreadTid, -10);
                         }
                     }
                 } else {
@@ -13410,7 +13436,7 @@
             if (r == null) {
                 throw new IllegalArgumentException();
             }
-            return r.task.getTopActivity() == r;
+            return r.getTask().getTopActivity() == r;
         }
     }
 
@@ -13496,7 +13522,7 @@
                 if (sender == null) {
                     uid = sourceUid;
                 } else {
-                    uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                    uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
                 }
                 BatteryStatsImpl.Uid.Pkg pkg =
                     stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
@@ -13519,7 +13545,7 @@
             if (sender == null) {
                 uid = sourceUid;
             } else {
-                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
             }
             mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
         }
@@ -13538,14 +13564,14 @@
             if (sender == null) {
                 uid = sourceUid;
             } else {
-                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
             }
             mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
         }
     }
 
     public boolean killPids(int[] pids, String pReason, boolean secure) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killPids only available to the system");
         }
         String reason = (pReason == null) ? "Unknown" : pReason;
@@ -13611,7 +13637,7 @@
 
     @Override
     public boolean killProcessesBelowForeground(String reason) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killProcessesBelowForeground() only available to system");
         }
 
@@ -13619,7 +13645,7 @@
     }
 
     private boolean killProcessesBelowAdj(int belowAdj, String reason) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killProcessesBelowAdj() only available to system");
         }
 
@@ -13696,7 +13722,7 @@
                 Log.i(TAG, "Shutting down activity manager...");
                 shutdown(10000);
                 Log.i(TAG, "Shutdown complete, restarting!");
-                Process.killProcess(Process.myPid());
+                killProcess(myPid());
                 System.exit(10);
             }
         };
@@ -14040,7 +14066,7 @@
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, Process.SYSTEM_UID,
+                        null, false, false, MY_PID, SYSTEM_UID,
                         currentUserId);
                 intent = new Intent(Intent.ACTION_USER_STARTING);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -14054,7 +14080,7 @@
                             }
                         }, 0, null, null,
                         new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
             } catch (Throwable t) {
                 Slog.wtf(TAG, "Failed sending first user broadcasts", t);
             } finally {
@@ -15928,8 +15954,9 @@
             }
             needSep = true;
             synchronized (this) {
-                if (lastTask != r.task) {
-                    lastTask = r.task;
+                final TaskRecord task = r.getTask();
+                if (lastTask != task) {
+                    lastTask = task;
                     pw.print("TASK "); pw.print(lastTask.affinity);
                             pw.print(" id="); pw.print(lastTask.taskId);
                             pw.print(" userId="); pw.println(lastTask.userId);
@@ -16698,22 +16725,22 @@
     private final long[] getKsmInfo() {
         long[] longOut = new long[4];
         final int[] SINGLE_LONG_FORMAT = new int[] {
-            Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+            PROC_SPACE_TERM| PROC_OUT_LONG
         };
         long[] longTmp = new long[1];
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+        readProcFile("/sys/kernel/mm/ksm/pages_shared",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+        readProcFile("/sys/kernel/mm/ksm/pages_sharing",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+        readProcFile("/sys/kernel/mm/ksm/pages_unshared",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+        readProcFile("/sys/kernel/mm/ksm/pages_volatile",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         return longOut;
@@ -17643,7 +17670,6 @@
      */
     private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
-        Slog.d(TAG, "cleanUpApplicationRecord -- " + app.pid);
         if (index >= 0) {
             removeLruProcessLocked(app);
             ProcessList.remove(app.pid);
@@ -17990,7 +18016,7 @@
             String className, int flags) {
         boolean result = false;
         // For apps that don't have pre-defined UIDs, check for permission
-        if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+        if (UserHandle.getAppId(aInfo.uid) >= FIRST_APPLICATION_UID) {
             if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
                 if (ActivityManager.checkUidPermission(
                         INTERACT_ACROSS_USERS,
@@ -18009,7 +18035,7 @@
             result = true;
         } else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
             // Phone app and persistent apps are allowed to export singleuser providers.
-            result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
+            result = UserHandle.isSameApp(aInfo.uid, PHONE_UID)
                     || (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         }
         if (DEBUG_MU) Slog.v(TAG_MU,
@@ -18027,8 +18053,8 @@
     boolean isValidSingletonCall(int callingUid, int componentUid) {
         int componentAppId = UserHandle.getAppId(componentUid);
         return UserHandle.isSameApp(callingUid, componentUid)
-                || componentAppId == Process.SYSTEM_UID
-                || componentAppId == Process.PHONE_UID
+                || componentAppId == SYSTEM_UID
+                || componentAppId == PHONE_UID
                 || ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, componentUid)
                         == PackageManager.PERMISSION_GRANTED;
     }
@@ -18269,7 +18295,7 @@
     // =========================================================
 
     private boolean isInstantApp(ProcessRecord record, String callerPackage, int uid) {
-        if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+        if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
             return false;
         }
         // Easy case -- we have the app's ProcessRecord.
@@ -18330,7 +18356,7 @@
                             + " (pid=" + Binder.getCallingPid()
                             + ") when registering receiver " + receiver);
                 }
-                if (callerApp.info.uid != Process.SYSTEM_UID &&
+                if (callerApp.info.uid != SYSTEM_UID &&
                         !callerApp.pkgList.containsKey(callerPackage) &&
                         !"android".equals(callerPackage)) {
                     throw new SecurityException("Given caller package " + callerPackage
@@ -18547,7 +18573,7 @@
             for (int user : users) {
                 // Skip users that have Shell restrictions, with exception of always permitted
                 // Shell broadcasts
-                if (callingUid == Process.SHELL_UID
+                if (callingUid == SHELL_UID
                         && mUserController.hasUserRestriction(
                                 UserManager.DISALLOW_DEBUGGING_FEATURES, user)
                         && !isPermittedShellBroadcast(intent)) {
@@ -18731,7 +18757,7 @@
         // and upgrade steps.
 
         if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
-            if ((callingUid != Process.SYSTEM_UID
+            if ((callingUid != SYSTEM_UID
                     || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                     && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                 Slog.w(TAG, "Skipping broadcast of " + intent
@@ -18775,11 +18801,11 @@
 
         final boolean isCallerSystem;
         switch (UserHandle.getAppId(callingUid)) {
-            case Process.ROOT_UID:
-            case Process.SYSTEM_UID:
-            case Process.PHONE_UID:
-            case Process.BLUETOOTH_UID:
-            case Process.NFC_UID:
+            case ROOT_UID:
+            case SYSTEM_UID:
+            case PHONE_UID:
+            case BLUETOOTH_UID:
+            case NFC_UID:
                 isCallerSystem = true;
                 break;
             default:
@@ -19155,7 +19181,7 @@
             receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
         }
         if (intent.getComponent() == null) {
-            if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
+            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                 // Query one target user at a time, excluding shell-restricted users
                 for (int i = 0; i < users.length; i++) {
                     if (mUserController.hasUserRestriction(
@@ -19397,8 +19423,8 @@
 
         if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
             switch (Binder.getCallingUid()) {
-                case Process.ROOT_UID:
-                case Process.SHELL_UID:
+                case ROOT_UID:
+                case SHELL_UID:
                     break;
                 default:
                     Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "
@@ -19853,7 +19879,7 @@
 
     private void enforceWriteSettingsPermission(String func) {
         int uid = Binder.getCallingUid();
-        if (uid == Process.ROOT_UID) {
+        if (uid == ROOT_UID) {
             return;
         }
 
@@ -20051,7 +20077,7 @@
                 | Intent.FLAG_RECEIVER_FOREGROUND
                 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
         broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                 UserHandle.USER_ALL);
         if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
             intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
@@ -20062,7 +20088,7 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             }
             broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                    AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                    AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                     UserHandle.USER_ALL);
         }
 
@@ -20562,8 +20588,9 @@
                     app.cached = false;
                     app.empty = false;
                     foregroundActivities = true;
-                    if (r.task != null && minLayer > 0) {
-                        final int layer = r.task.mLayerRank;
+                    final TaskRecord task = r.getTask();
+                    if (task != null && minLayer > 0) {
+                        final int layer = task.mLayerRank;
                         if (layer >= 0 && minLayer > layer) {
                             minLayer = layer;
                         }
@@ -21535,27 +21562,27 @@
                 int processGroup;
                 switch (app.curSchedGroup) {
                     case ProcessList.SCHED_GROUP_BACKGROUND:
-                        processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
                         break;
                     case ProcessList.SCHED_GROUP_TOP_APP:
                     case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
-                        processGroup = Process.THREAD_GROUP_TOP_APP;
+                        processGroup = THREAD_GROUP_TOP_APP;
                         break;
                     default:
-                        processGroup = Process.THREAD_GROUP_DEFAULT;
+                        processGroup = THREAD_GROUP_DEFAULT;
                         break;
                 }
                 long oldId = Binder.clearCallingIdentity();
                 try {
-                    Process.setProcessGroup(app.pid, processGroup);
+                    setProcessGroup(app.pid, processGroup);
                     if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         // do nothing if we already switched to RT
                         if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                             // Switch VR thread for app to SCHED_FIFO
                             if (mVrState == VR_MODE && app.vrThreadTid != 0) {
                                 try {
-                                    Process.setThreadScheduler(app.vrThreadTid,
-                                        Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                    setThreadScheduler(app.vrThreadTid,
+                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                     mTopAppVrThreadTid = app.vrThreadTid;
                                 } catch (IllegalArgumentException e) {
                                     // thread died, ignore
@@ -21563,17 +21590,17 @@
                             }
                             if (mUseFifoUiScheduling) {
                                 // Switch UI pipeline for app to SCHED_FIFO
-                                app.savedPriority = Process.getThreadPriority(app.pid);
+                                app.savedPriority = getThreadPriority(app.pid);
                                 try {
-                                    Process.setThreadScheduler(app.pid,
-                                        Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                    setThreadScheduler(app.pid,
+                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                 } catch (IllegalArgumentException e) {
                                     // thread died, ignore
                                 }
                                 if (app.renderThreadTid != 0) {
                                     try {
-                                        Process.setThreadScheduler(app.renderThreadTid,
-                                            Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                        setThreadScheduler(app.renderThreadTid,
+                                            SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                     } catch (IllegalArgumentException e) {
                                         // thread died, ignore
                                     }
@@ -21588,10 +21615,10 @@
                                 }
                             } else {
                                 // Boost priority for top app UI and render threads
-                                Process.setThreadPriority(app.pid, -10);
+                                setThreadPriority(app.pid, -10);
                                 if (app.renderThreadTid != 0) {
                                     try {
-                                        Process.setThreadPriority(app.renderThreadTid, -10);
+                                        setThreadPriority(app.renderThreadTid, -10);
                                     } catch (IllegalArgumentException e) {
                                         // thread died, ignore
                                     }
@@ -21603,23 +21630,23 @@
                         // Reset VR thread to SCHED_OTHER
                         // Safe to do even if we're not in VR mode
                         if (app.vrThreadTid != 0) {
-                            Process.setThreadScheduler(app.vrThreadTid, Process.SCHED_OTHER, 0);
+                            setThreadScheduler(app.vrThreadTid, SCHED_OTHER, 0);
                             mTopAppVrThreadTid = 0;
                         }
                         if (mUseFifoUiScheduling) {
                             // Reset UI pipeline to SCHED_OTHER
-                            Process.setThreadScheduler(app.pid, Process.SCHED_OTHER, 0);
-                            Process.setThreadPriority(app.pid, app.savedPriority);
+                            setThreadScheduler(app.pid, SCHED_OTHER, 0);
+                            setThreadPriority(app.pid, app.savedPriority);
                             if (app.renderThreadTid != 0) {
-                                Process.setThreadScheduler(app.renderThreadTid,
-                                    Process.SCHED_OTHER, 0);
-                                Process.setThreadPriority(app.renderThreadTid, -4);
+                                setThreadScheduler(app.renderThreadTid,
+                                    SCHED_OTHER, 0);
+                                setThreadPriority(app.renderThreadTid, -4);
                             }
                         } else {
                             // Reset priority for top app UI and render threads
-                            Process.setThreadPriority(app.pid, 0);
+                            setThreadPriority(app.pid, 0);
                             if (app.renderThreadTid != 0) {
-                                Process.setThreadPriority(app.renderThreadTid, 0);
+                                setThreadPriority(app.renderThreadTid, 0);
                             }
                         }
                     }
@@ -22729,7 +22756,7 @@
 
     /** This method sends the specified signal to each of the persistent apps */
     public void signalPersistentProcesses(int sig) throws RemoteException {
-        if (sig != Process.SIGNAL_USR1) {
+        if (sig != SIGNAL_USR1) {
             throw new SecurityException("Only SIGNAL_USR1 is allowed");
         }
 
@@ -22743,7 +22770,7 @@
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord r = mLruProcesses.get(i);
                 if (r.thread != null && r.persistent) {
-                    Process.sendSignal(r.pid, sig);
+                    sendSignal(r.pid, sig);
                 }
             }
         }
@@ -23884,7 +23911,7 @@
         final boolean updateFrameworkRes = packagesToUpdate.contains("android");
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             final ProcessRecord app = mLruProcesses.get(i);
-            if (app.thread == null || app.pid == Process.myPid()) {
+            if (app.thread == null) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cbb51e1..3a29414 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -229,7 +229,7 @@
     private int theme;              // resource identifier of activity's theme.
     private int realTheme;          // actual theme resource we will use, never 0.
     private int windowFlags;        // custom window flags for preview window.
-    TaskRecord task;        // the task this is in.
+    private TaskRecord task;        // the task this is in.
     private long createTime = System.currentTimeMillis();
     long displayStartTime;  // when we started launching this activity
     long fullyDrawnStartTime; // when we started launching this activity
@@ -686,9 +686,48 @@
 
     @Override
     protected ConfigurationContainer getParent() {
+        return getTask();
+    }
+
+    TaskRecord getTask() {
         return task;
     }
 
+    /**
+     * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent.
+     * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord}
+     * children. However, this method will clean up references to this {@link ActivityRecord} in
+     * {@link ActivityStack}.
+     * @param task The new parent {@link TaskRecord}.
+     */
+    void setTask(TaskRecord task) {
+        setTask(task, false /*reparenting*/);
+    }
+
+    /**
+     * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}.
+     */
+    void setTask(TaskRecord task, boolean reparenting) {
+        // Do nothing if the {@link TaskRecord} is the same as the current {@link getTask}.
+        if (task != null && task == getTask()) {
+            return;
+        }
+
+        final ActivityStack stack = getStack();
+
+        // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
+        // {@link ActivityRecord} from its current {@link ActivityStack}.
+        if (!reparenting && stack != null && (task == null || stack != task.getStack())) {
+            stack.onActivityRemovedFromStack(this);
+        }
+
+        this.task = task;
+
+        if (!reparenting) {
+            onParentChanged();
+        }
+    }
+
     static class Token extends IApplicationToken.Stub {
         private final WeakReference<ActivityRecord> weakActivity;
 
@@ -925,8 +964,8 @@
         // Must reparent first in window manager
         mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
 
-        // Remove the activity from the old task and add it to the new task
-        prevTask.removeActivity(this);
+        // Remove the activity from the old task and add it to the new task.
+        prevTask.removeActivity(this, true /*reparenting*/);
 
         newTask.addActivityAtIndex(position, this);
     }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ee37463..f13b11e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -116,6 +116,7 @@
 import android.util.SparseArray;
 import android.view.Display;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
@@ -725,7 +726,7 @@
         if (r == null) {
             return null;
         }
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         final ActivityStack stack = r.getStack();
         if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
             if (stack != this) Slog.w(TAG,
@@ -934,7 +935,7 @@
 
             if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                     + taskIntent.getComponent().flattenToShortString()
-                    + "/aff=" + r.task.rootAffinity + " to new cls="
+                    + "/aff=" + r.getTask().rootAffinity + " to new cls="
                     + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
             // TODO Refactor to remove duplications. Check if logic can be simplified.
             if (taskIntent != null && taskIntent.getComponent() != null &&
@@ -1049,8 +1050,9 @@
 
     void addRecentActivityLocked(ActivityRecord r) {
         if (r != null) {
-            mRecentTasks.addLocked(r.task);
-            r.task.touchActiveTime();
+            final TaskRecord task = r.getTask();
+            mRecentTasks.addLocked(task);
+            task.touchActiveTime();
         }
     }
 
@@ -1226,11 +1228,12 @@
         mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
         prev.state = ActivityState.PAUSING;
-        prev.task.touchActiveTime();
+        prev.getTask().touchActiveTime();
         clearLaunchTime(prev);
         final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
         if (mService.mHasRecents
-                && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
+                && (next == null || next.noDisplay || next.getTask() != prev.getTask()
+                || uiSleeping)) {
             prev.mUpdateTaskThumbnailWhenHidden = true;
         }
         stopFullyDrawnTraceIfNeeded();
@@ -1457,7 +1460,7 @@
     // Find the first visible activity above the passed activity and if it is translucent return it
     // otherwise return null;
     ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
-        TaskRecord task = r.task;
+        TaskRecord task = r.getTask();
         if (task == null) {
             return null;
         }
@@ -1604,7 +1607,7 @@
             // Otherwise, the docked stack is always visible, except in the case where the top
             // running activity task in the focus stack doesn't support any form of resizing but we
             // show it for the home task even though it's not resizable.
-            final TaskRecord task = r != null ? r.task : null;
+            final TaskRecord task = r != null ? r.getTask() : null;
             return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE
                     : STACK_INVISIBLE;
         }
@@ -2157,8 +2160,9 @@
         mResumedActivity = r;
         r.state = ActivityState.RESUMED;
         mService.setResumedActivityUncheckLocked(r, reason);
-        r.task.touchActiveTime();
-        mRecentTasks.addLocked(r.task);
+        final TaskRecord task = r.getTask();
+        task.touchActiveTime();
+        mRecentTasks.addLocked(task);
     }
 
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
@@ -2207,8 +2211,8 @@
             return false;
         }
 
-        final TaskRecord nextTask = next.task;
-        final TaskRecord prevTask = prev != null ? prev.task : null;
+        final TaskRecord nextTask = next.getTask();
+        final TaskRecord prevTask = prev != null ? prev.getTask() : null;
         if (prevTask != null && prevTask.getStack() == this &&
                 prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
@@ -2373,7 +2377,7 @@
                     anim = false;
                     mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                 } else {
-                    mWindowManager.prepareAppTransition(prev.task == next.task
+                    mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
                             ? TRANSIT_ACTIVITY_CLOSE
                             : TRANSIT_TASK_CLOSE, false);
                 }
@@ -2385,7 +2389,7 @@
                     anim = false;
                     mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                 } else {
-                    mWindowManager.prepareAppTransition(prev.task == next.task
+                    mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
                             ? TRANSIT_ACTIVITY_OPEN
                             : next.mLaunchTaskBehind
                                     ? TRANSIT_TASK_OPEN_BEHIND
@@ -2522,7 +2526,8 @@
                 next.notifyAppResumed(next.stopped, allowSavedSurface);
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
-                        System.identityHashCode(next), next.task.taskId, next.shortComponentName);
+                        System.identityHashCode(next), next.getTask().taskId,
+                        next.shortComponentName);
 
                 next.sleeping = false;
                 mService.showUnsupportedZoomDialogIfNeededLocked(next);
@@ -2696,9 +2701,15 @@
             return;
         }
 
-        // If the task was launched from the assistant stack, set the return type to assistant
         final ActivityStack lastStack = mStackSupervisor.getLastStack();
-        if (lastStack != null && lastStack.isAssistantStack()) {
+
+        // If there is no last task, do not set task to return to
+        if (lastStack == null) {
+            return;
+        }
+
+        // If the task was launched from the assistant stack, set the return type to assistant
+        if (lastStack.isAssistantStack()) {
             task.setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
             return;
         }
@@ -2721,7 +2732,7 @@
 
     final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
             boolean newTask, boolean keepCurTransition, ActivityOptions options) {
-        TaskRecord rTask = r.task;
+        TaskRecord rTask = r.getTask();
         final int taskId = rTask.taskId;
         // mLaunchTaskBehind tasks get placed at the back of the task stack.
         if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
@@ -2740,7 +2751,7 @@
                     // All activities in task are finishing.
                     continue;
                 }
-                if (task == r.task) {
+                if (task == rTask) {
                     // Here it is!  Now, if this is not yet visible to the
                     // user, then just add it without starting; it will
                     // get started when the user navigates back to it.
@@ -2762,13 +2773,14 @@
 
         // If we are not placing the new activity frontmost, we do not want to deliver the
         // onUserLeaving callback to the actual frontmost activity
-        if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
+        final TaskRecord activityTask = r.getTask();
+        if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
             mStackSupervisor.mUserLeaving = false;
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "startActivity() behind front, mUserLeaving=false");
         }
 
-        task = r.task;
+        task = activityTask;
 
         // Slot the activity into the history stack and proceed
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
@@ -2795,7 +2807,8 @@
                     } else {
                         // If a new task is being launched, then mark the existing top activity as
                         // supporting picture-in-picture while pausing
-                        if (focusedTopActivity != null) {
+                        if (focusedTopActivity != null &&
+                                focusedTopActivity.getStack().getStackId() != PINNED_STACK_ID) {
                             focusedTopActivity.supportsPictureInPictureWhilePausing = true;
                         }
                         transit = TRANSIT_TASK_OPEN;
@@ -2829,11 +2842,12 @@
                 // "has the same starting icon" as the next one.  This allows the
                 // window manager to keep the previous window it had previously
                 // created, if it still had one.
-                ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
+                TaskRecord prevTask = r.getTask();
+                ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
                 if (prev != null) {
                     // We don't want to reuse the previous starting preview if:
                     // (1) The current activity is in a different task.
-                    if (prev.task != r.task) {
+                    if (prev.getTask() != prevTask) {
                         prev = null;
                     }
                     // (2) The current activity is already displayed.
@@ -2852,7 +2866,7 @@
 
     private boolean isTaskSwitch(ActivityRecord r,
             ActivityRecord topFocusedActivity) {
-        return topFocusedActivity != null && r.task != topFocusedActivity.task;
+        return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
     }
 
     /**
@@ -2919,20 +2933,20 @@
                         !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
                                 mTaskHistory.get(0).mActivities.get(0) : null;
                 if (bottom != null && target.taskAffinity != null
-                        && target.taskAffinity.equals(bottom.task.affinity)) {
+                        && target.taskAffinity.equals(bottom.getTask().affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    targetTask = bottom.task;
+                    targetTask = bottom.getTask();
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
-                            + " out to bottom task " + bottom.task);
+                            + " out to bottom task " + targetTask);
                 } else {
                     targetTask = createTaskRecord(
                             mStackSupervisor.getNextTaskIdForUserLocked(target.userId),
                             target.info, null, null, null, false, target.mActivityType);
                     targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
-                            + " out to new task " + target.task);
+                            + " out to new task " + targetTask);
                 }
 
                 boolean noOptions = canMoveOptions;
@@ -2954,7 +2968,7 @@
                             "Removing activity " + p + " from task=" + task + " adding to task="
                             + targetTask + " Callers=" + Debug.getCallers(4));
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                            "Pushing next activity " + p + " out to target's task " + target.task);
+                            "Pushing next activity " + p + " out to target's task " + target);
                     p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded");
                 }
 
@@ -3125,13 +3139,13 @@
         boolean forceReset =
                 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
         if (ACTIVITY_INACTIVE_RESET_TIME > 0
-                && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
+                && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
             if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
                 forceReset = true;
             }
         }
 
-        final TaskRecord task = taskTop.task;
+        final TaskRecord task = taskTop.getTask();
 
         /** False until we evaluate the TaskRecord associated with taskTop. Switches to true
          * for remaining tasks. Used for later tasks to reparent to task. */
@@ -3214,7 +3228,7 @@
                 // stack as long as there is a running activity.
                 return;
             } else {
-                final TaskRecord task = r.task;
+                final TaskRecord task = r.getTask();
                 final boolean isAssistantOrOverAssistant = task.getStack().isAssistantStack() ||
                         task.isOverAssistantStack();
                 if (r.frontOfTask && task == topTask() &&
@@ -3373,10 +3387,12 @@
         }
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
-        int taskNdx = mTaskHistory.indexOf(r.task);
-        int activityNdx = r.task.mActivities.indexOf(r);
+        finishedTask = r.getTask();
+        int taskNdx = mTaskHistory.indexOf(finishedTask);
+        final TaskRecord task = finishedTask;
+        int activityNdx = task.mActivities.indexOf(r);
         finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
-        finishedTask = r.task;
+        finishedTask = task;
         // Also terminate any activities below it that aren't yet
         // stopped, to avoid a situation where one will get
         // re-start our crashing activity once it gets resumed again.
@@ -3446,7 +3462,7 @@
     }
 
     final boolean finishActivityAffinityLocked(ActivityRecord r) {
-        ArrayList<ActivityRecord> activities = r.task.mActivities;
+        ArrayList<ActivityRecord> activities = r.getTask().mActivities;
         for (int index = activities.indexOf(r); index >= 0; --index) {
             ActivityRecord cur = activities.get(index);
             if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) {
@@ -3511,7 +3527,7 @@
         mWindowManager.deferSurfaceLayout();
         try {
             r.makeFinishingLocked();
-            final TaskRecord task = r.task;
+            final TaskRecord task = r.getTask();
             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                     r.userId, System.identityHashCode(r),
                     task.taskId, r.shortComponentName, reason);
@@ -3700,23 +3716,24 @@
     final boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
         // Basic case: for simple app-centric recents, we need to recreate
         // the task if the affinity has changed.
-        if (srec == null || srec.task.affinity == null ||
-                !srec.task.affinity.equals(destAffinity)) {
+        if (srec == null || srec.getTask().affinity == null ||
+                !srec.getTask().affinity.equals(destAffinity)) {
             return true;
         }
         // Document-centric case: an app may be split in to multiple documents;
         // they need to re-create their task if this current activity is the root
         // of a document, unless simply finishing it will return them to the the
         // correct app behind.
-        if (srec.frontOfTask && srec.task != null && srec.task.getBaseIntent() != null
-                && srec.task.getBaseIntent().isDocument()) {
+        final TaskRecord task = srec.getTask();
+        if (srec.frontOfTask && task != null && task.getBaseIntent() != null
+                && task.getBaseIntent().isDocument()) {
             // Okay, this activity is at the root of its task.  What to do, what to do...
-            if (srec.task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) {
+            if (task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) {
                 // Finishing won't return to an application, so we need to recreate.
                 return true;
             }
             // We now need to get the task below it to determine what to do.
-            int taskIdx = mTaskHistory.indexOf(srec.task);
+            int taskIdx = mTaskHistory.indexOf(task);
             if (taskIdx <= 0) {
                 Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
                 return false;
@@ -3726,7 +3743,7 @@
                 return true;
             }
             TaskRecord prevTask = mTaskHistory.get(taskIdx);
-            if (!srec.task.affinity.equals(prevTask.affinity)) {
+            if (!task.affinity.equals(prevTask.affinity)) {
                 // These are different apps, so need to recreate.
                 return true;
             }
@@ -3736,7 +3753,7 @@
 
     final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
-        final TaskRecord task = srec.task;
+        final TaskRecord task = srec.getTask();
         final ArrayList<ActivityRecord> activities = task.mActivities;
         final int start = activities.indexOf(srec);
         if (!mTaskHistory.contains(task) || (start < 0)) {
@@ -3815,6 +3832,22 @@
         Binder.restoreCallingIdentity(origId);
         return foundParentInTask;
     }
+
+    /**
+     * Remove any state associated with the {@link ActivityRecord}. This should be called whenever
+     * an activity moves away from the stack.
+     */
+    void onActivityRemovedFromStack(ActivityRecord r) {
+        if (mResumedActivity == r) {
+            mResumedActivity = null;
+        }
+        if (mPausingActivity == r) {
+            mPausingActivity = null;
+        }
+
+        removeTimeoutsForActivityLocked(r);
+    }
+
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
@@ -3825,12 +3858,7 @@
      * Note: Call before #removeActivityFromHistoryLocked.
      */
     private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
-        if (mResumedActivity == r) {
-            mResumedActivity = null;
-        }
-        if (mPausingActivity == r) {
-            mPausingActivity = null;
-        }
+        onActivityRemovedFromStack(r);
 
         r.deferRelaunchUntilPaused = false;
         r.frozenBeforeDestroy = false;
@@ -3897,7 +3925,7 @@
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
         r.app = null;
         r.removeWindowContainer();
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         final boolean lastActivity = task != null ? task.removeActivity(r) : false;
         // If we are removing the last activity in the task, not including task overlay activities,
         // then fall through into the block below to remove the entire task itself
@@ -4043,7 +4071,7 @@
                         + ", app=" + (r.app != null ? r.app.processName : "(null)"));
         EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
                 r.userId, System.identityHashCode(r),
-                r.task.taskId, r.shortComponentName, reason);
+                r.getTask().taskId, r.shortComponentName, reason);
 
         boolean removedFromHistory = false;
 
@@ -4275,7 +4303,7 @@
                             Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
                             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                                     r.userId, System.identityHashCode(r),
-                                    r.task.taskId, r.shortComponentName,
+                                    r.getTask().taskId, r.shortComponentName,
                                     "proc died without state saved");
                             if (r.state == ActivityState.RESUMED) {
                                 mService.updateUsageStats(r, false);
@@ -4403,7 +4431,7 @@
         }
         // If a new task is moved to the front, then mark the existing top activity as supporting
         // picture-in-picture while paused
-        if (topActivity != null) {
+        if (topActivity != null && topActivity.getStack().getStackId() != PINNED_STACK_ID) {
             topActivity.supportsPictureInPictureWhilePausing = true;
         }
 
@@ -4529,7 +4557,7 @@
             }
         }
 
-        final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+        final TaskRecord task = mResumedActivity != null ? mResumedActivity.getTask() : null;
         if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
             if (!mService.mBooting && !mService.mBooted) {
                 // Not ready yet!
@@ -4570,7 +4598,7 @@
             return;
         }
 
-        final TaskRecord startTask = start.task;
+        final TaskRecord startTask = start.getTask();
         boolean behindFullscreen = false;
         boolean updatedConfig = false;
 
@@ -4578,7 +4606,7 @@
             final TaskRecord task = mTaskHistory.get(taskIndex);
             final ArrayList<ActivityRecord> activities = task.mActivities;
             int activityIndex =
-                    (start.task == task) ? activities.indexOf(start) : activities.size() - 1;
+                    (start.getTask() == task) ? activities.indexOf(start) : activities.size() - 1;
             for (; activityIndex >= 0; --activityIndex) {
                 final ActivityRecord r = activities.get(activityIndex);
                 updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */,
@@ -4739,7 +4767,7 @@
                                 || filterByClasses.contains(r.realActivity.getClassName())))
                         || (packageName == null && r.userId == userId);
                 if ((userId == UserHandle.USER_ALL || r.userId == userId)
-                        && (sameComponent || r.task == lastTask)
+                        && (sameComponent || r.getTask() == lastTask)
                         && (r.app == null || evenPersistent || !r.app.persistent)) {
                     if (!doit) {
                         if (r.finishing) {
@@ -4765,7 +4793,7 @@
                         }
                         r.app = null;
                     }
-                    lastTask = r.task;
+                    lastTask = r.getTask();
                     if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
                             true)) {
                         // r has been deleted from mActivities, accommodate.
@@ -4816,7 +4844,7 @@
 
                 if (DEBUG_ALL) Slog.v(
                     TAG, r.intent.getComponent().flattenToShortString()
-                    + ": task=" + r.task);
+                    + ": task=" + r.getTask());
             }
 
             RunningTaskInfo ci = new RunningTaskInfo();
@@ -4832,8 +4860,8 @@
                 topTask = false;
             }
 
-            if (top.task != null) {
-                ci.description = top.task.lastDescription;
+            if (top.getTask() != null) {
+                ci.description = top.getTask().lastDescription;
             }
             ci.numActivities = numActivities;
             ci.numRunning = numRunning;
@@ -4982,9 +5010,8 @@
             task.removeWindowContainer();
         }
 
-        final ActivityRecord r = mResumedActivity;
-        if (r != null && r.task == task) {
-            mResumedActivity = null;
+        for (ActivityRecord record : task.mActivities) {
+            onActivityRemovedFromStack(record);
         }
 
         final int taskNdx = mTaskHistory.indexOf(task);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f16849d..b72cd73 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -164,6 +164,7 @@
 import android.view.InputEvent;
 import android.view.Surface;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -173,6 +174,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.wm.StackWindowController;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -553,9 +555,9 @@
         }
     }
 
-    public ActivityStackSupervisor(ActivityManagerService service) {
+    public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
         mService = service;
-        mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
+        mHandler = new ActivityStackSupervisorHandler(looper);
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
         mKeyguardController = new KeyguardController(service, this);
     }
@@ -722,7 +724,7 @@
         }
 
         if (prev != null) {
-            prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+            prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
         }
 
         mHomeStack.moveHomeStackTaskToTop();
@@ -1314,7 +1316,7 @@
         mService.updateLruProcessLocked(app, true, null);
         mService.updateOomAdjLocked();
 
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
                 task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
             setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
@@ -2622,7 +2624,7 @@
                 }
 
                 for (int k = 0; k < proc.activities.size(); k++) {
-                    TaskRecord otherTask = proc.activities.get(k).task;
+                    TaskRecord otherTask = proc.activities.get(k).getTask();
                     if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
                         // Don't kill process(es) that has an activity in a different task that is
                         // also in recents.
@@ -2837,7 +2839,7 @@
         final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
 
         try {
-            final TaskRecord task = r.task;
+            final TaskRecord task = r.getTask();
 
             if (r == task.getStack().getVisibleBehindActivity()) {
                 // An activity can't be pinned and visible behind at the same time. Go ahead and
@@ -2910,7 +2912,7 @@
             return false;
         }
 
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         final ActivityStack stack = r.getStack();
         if (stack == null) {
             Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
@@ -3203,7 +3205,7 @@
 
     // Called when WindowManager has finished animating the launchingBehind activity to the back.
     private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         final ActivityStack stack = task.getStack();
 
         r.mLaunchTaskBehind = false;
@@ -3216,7 +3218,7 @@
         // task has been shown briefly
         final ActivityRecord top = stack.topActivity();
         if (top != null) {
-            top.task.touchActiveTime();
+            top.getTask().touchActiveTime();
         }
     }
 
@@ -3315,17 +3317,19 @@
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
                 continue;
             }
-            if (r.task != null) {
-                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + r.task
+
+            final TaskRecord task = r.getTask();
+            if (task != null) {
+                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
                         + " from " + r);
                 if (firstTask == null) {
-                    firstTask = r.task;
-                } else if (firstTask != r.task) {
+                    firstTask = task;
+                } else if (firstTask != task) {
                     if (tasks == null) {
                         tasks = new ArraySet<>();
                         tasks.add(firstTask);
                     }
-                    tasks.add(r.task);
+                    tasks.add(task);
                 }
             }
         }
@@ -3664,8 +3668,8 @@
                 pw.println(header2);
                 header2 = null;
             }
-            if (lastTask != r.task) {
-                lastTask = r.task;
+            if (lastTask != r.getTask()) {
+                lastTask = r.getTask();
                 pw.print(prefix);
                 pw.print(full ? "* " : "  ");
                 pw.println(lastTask);
@@ -4080,7 +4084,7 @@
             }
         }
         final ActivityRecord r = topRunningActivityLocked();
-        final TaskRecord task = r != null ? r.task : null;
+        final TaskRecord task = r != null ? r.getTask() : null;
         if (mLockTaskModeTasks.isEmpty() && task != null
                 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
             // This task must have just been authorized.
@@ -4390,19 +4394,24 @@
             synchronized (mService) {
                 mStackId = stackId;
                 mActivityDisplay = activityDisplay;
-                switch (mStackId) {
-                    case PINNED_STACK_ID:
-                        new PinnedActivityStack(this, mRecentTasks, onTop);
-                        break;
-                    default:
-                        new ActivityStack(this, mRecentTasks, onTop);
-                        break;
-                }
                 mIdString = "ActivtyContainer{" + mStackId + "}";
+
+                createStack(stackId, onTop);
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
             }
         }
 
+        protected void createStack(int stackId, boolean onTop) {
+            switch (stackId) {
+                case PINNED_STACK_ID:
+                    new PinnedActivityStack(this, mRecentTasks, onTop);
+                    break;
+                default:
+                    new ActivityStack(this, mRecentTasks, onTop);
+                    break;
+            }
+        }
+
         /**
          * Adds the stack to specified display. Also calls WindowManager to do the same from
          * {@link ActivityStack#reparent(ActivityDisplay, boolean)}.
@@ -4926,7 +4935,7 @@
 
             mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
                     ActivityManager.START_TASK_TO_FRONT,
-                    sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
+                    sourceRecord != null ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID,
                     sourceRecord, task.getStack());
             return ActivityManager.START_TASK_TO_FRONT;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 547161a..cafc4f0 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -188,10 +188,10 @@
         }
 
         ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
-        if (homeActivityRecord != null && homeActivityRecord.task != null) {
+        if (homeActivityRecord != null && homeActivityRecord.getTask() != null) {
             // Showing credential confirmation activity in home task to avoid stopping multi-windowed
             // mode after showing the full-screen credential confirmation activity.
-            mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId);
+            mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId);
         }
 
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 18e7408..b408569 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -79,7 +79,6 @@
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
 import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
@@ -87,8 +86,6 @@
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
 
-import static java.lang.Integer.MAX_VALUE;
-
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -335,7 +332,7 @@
         }
 
         if (err == ActivityManager.START_SUCCESS && sourceRecord != null
-                && sourceRecord.task.voiceSession != null) {
+                && sourceRecord.getTask().voiceSession != null) {
             // If this activity is being launched as part of a voice session, we need
             // to ensure that it is safe to do so.  If the upcoming activity will also
             // be part of the voice session, we can only launch it if it has explicitly
@@ -575,7 +572,7 @@
         // visibility instead of using this flag.
         final boolean noDisplayActivityOverHome = sourceRecord != null
                 && sourceRecord.noDisplay
-                && sourceRecord.task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE;
+                && sourceRecord.getTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE;
         if (startedActivityStackId == DOCKED_STACK_ID
                 && (prevFocusedStackId == HOME_STACK_ID || noDisplayActivityOverHome)) {
             final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID);
@@ -625,7 +622,7 @@
                 FLAG_ACTIVITY_TASK_ON_HOME);
         ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle)
                         : ActivityOptions.makeBasic());
-        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+        options.setLaunchTaskId(mSupervisor.getHomeActivity().getTask().taskId);
         mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
     }
 
@@ -763,7 +760,7 @@
                             newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
                                     hist.packageName);
                             newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
-                                    hist.task.taskId);
+                                    hist.getTask().taskId);
                         }
                         newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
                                 aInfo.packageName);
@@ -967,8 +964,8 @@
             // If we are not able to proceed, disassociate the activity from the task. Leaving an
             // activity in an incomplete state can lead to issues, such as performing operations
             // without a window container.
-            if (result != START_SUCCESS && mStartActivity.task != null) {
-                mStartActivity.task.removeActivity(mStartActivity);
+            if (result != START_SUCCESS && mStartActivity.getTask() != null) {
+                mStartActivity.getTask().removeActivity(mStartActivity);
             }
             mService.mWindowManager.continueSurfaceLayout();
         }
@@ -1002,7 +999,7 @@
             // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
             // still needs to be a lock task mode violation since the task gets cleared out and
             // the device would otherwise leave the locked task.
-            if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
+            if (mSupervisor.isLockTaskModeViolation(mReusedActivity.getTask(),
                     (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                             == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                 mSupervisor.showLockTaskToast();
@@ -1010,13 +1007,13 @@
                 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
 
-            if (mStartActivity.task == null) {
-                mStartActivity.task = mReusedActivity.task;
+            if (mStartActivity.getTask() == null) {
+                mStartActivity.setTask(mReusedActivity.getTask());
             }
-            if (mReusedActivity.task.intent == null) {
+            if (mReusedActivity.getTask().intent == null) {
                 // This task was started because of movement of the activity based on affinity...
                 // Now that we are actually launching it, we can assign the base intent.
-                mReusedActivity.task.setIntent(mStartActivity);
+                mReusedActivity.getTask().setIntent(mStartActivity);
             }
 
             // This code path leads to delivering a new intent, we want to make sure we schedule it
@@ -1025,7 +1022,7 @@
             if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                     || isDocumentLaunchesIntoExisting(mLaunchFlags)
                     || mLaunchSingleInstance || mLaunchSingleTask) {
-                final TaskRecord task = mReusedActivity.task;
+                final TaskRecord task = mReusedActivity.getTask();
 
                 // In this situation we want to remove all activities from the task up to the one
                 // being started. In most cases this means we are resetting the task to its initial
@@ -1037,17 +1034,17 @@
                 // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
                 // task reference is needed in the call below to
                 // {@link setTargetStackAndMoveToFrontIfNeeded}.
-                if (mReusedActivity.task == null) {
-                    mReusedActivity.task = task;
+                if (mReusedActivity.getTask() == null) {
+                    mReusedActivity.setTask(task);
                 }
 
                 if (top != null) {
                     if (top.frontOfTask) {
                         // Activity aliases may mean we use different intents for the top activity,
                         // so make sure the task now has the identity of the new intent.
-                        top.task.setIntent(mStartActivity);
+                        top.getTask().setIntent(mStartActivity);
                     }
-                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
                     top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                             mStartActivity.launchedFromPackage);
                 }
@@ -1098,7 +1095,7 @@
                 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                 || mLaunchSingleTop || mLaunchSingleTask);
         if (dontStart) {
-            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
             // For paranoia, make sure we have correctly resumed the top activity.
             topStack.mLastPausedActivity = null;
             if (mDoResume) {
@@ -1116,14 +1113,14 @@
             // Don't use mStartActivity.task to show the toast. We're not starting a new activity
             // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
             mSupervisor.handleNonResizableTaskIfNeeded(
-                    top.task, preferredLaunchStackId, topStack.mStackId);
+                    top.getTask(), preferredLaunchStackId, topStack.mStackId);
 
             return START_DELIVERED_TO_TOP;
         }
 
         boolean newTask = false;
         final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
-                ? mSourceRecord.task : null;
+                ? mSourceRecord.getTask() : null;
 
         // Should this be considered a new task?
         int result = START_SUCCESS;
@@ -1150,14 +1147,15 @@
         mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
                 mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
         if (mSourceRecord != null) {
-            mStartActivity.task.setTaskToReturnTo(mSourceRecord);
+            mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
         }
         if (newTask) {
             EventLog.writeEvent(
-                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
+                    mStartActivity.getTask().taskId);
         }
         ActivityStack.logStartActivity(
-                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
         mTargetStack.mLastPausedActivity = null;
 
         sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
@@ -1165,7 +1163,8 @@
         mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                 mOptions);
         if (mDoResume) {
-            final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
+            final ActivityRecord topTaskActivity =
+                    mStartActivity.getTask().topRunningActivityLocked();
             if (!mTargetStack.isFocusable()
                     || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                     && mStartActivity != topTaskActivity)) {
@@ -1197,7 +1196,7 @@
         mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
 
         mSupervisor.handleNonResizableTaskIfNeeded(
-                mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
+                mStartActivity.getTask(), preferredLaunchStackId, mTargetStack.mStackId);
 
         return START_SUCCESS;
     }
@@ -1424,7 +1423,7 @@
                     + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
             mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
             mNewTaskInfo = mSourceRecord.info;
-            mNewTaskIntent = mSourceRecord.task.intent;
+            mNewTaskIntent = mSourceRecord.getTask().intent;
         }
         mSourceRecord = null;
         mSourceStack = null;
@@ -1516,15 +1515,16 @@
         ActivityRecord curTop = (focusStack == null)
                 ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
 
-        if (curTop != null
-                && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
+        final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
+        if (topTask != null
+                && (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
                 && !mAvoidMoveToFront) {
             mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
             if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
-                    mSourceStack.topActivity().task == mSourceRecord.task)) {
+                    mSourceStack.topActivity().getTask() == mSourceRecord.getTask())) {
                 // We really do want to push this one into the user's face, right now.
                 if (mLaunchTaskBehind && mSourceRecord != null) {
-                    intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
+                    intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
                 }
                 mMovedOtherTask = true;
 
@@ -1539,13 +1539,13 @@
                             == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
                 if (!willClearTask) {
                     final ActivityStack launchStack = getLaunchStack(
-                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
+                            mStartActivity, mLaunchFlags, mStartActivity.getTask(), mOptions);
+                    final TaskRecord intentTask = intentActivity.getTask();
                     if (launchStack == null || launchStack == mTargetStack) {
                         // We only want to move to the front, if we aren't going to launch on a
                         // different stack. If we launch on a different stack, we will put the
                         // task on top there.
-                        mTargetStack.moveTaskToFrontLocked(
-                                intentActivity.task, mNoAnimation, mOptions,
+                        mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
                                 mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
                         mMovedToFront = true;
                     } else if (launchStack.mStackId == DOCKED_STACK_ID
@@ -1553,7 +1553,7 @@
                         if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                             // If we want to launch adjacent and mTargetStack is not the computed
                             // launch stack - move task to top of computed stack.
-                            intentActivity.task.reparent(launchStack.mStackId, ON_TOP,
+                            intentTask.reparent(launchStack.mStackId, ON_TOP,
                                     REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
                                     "launchToSide");
                         } else {
@@ -1561,8 +1561,8 @@
                             // We choose to move task to front instead of launching it adjacent
                             // when specific stack was requested explicitly and it appeared to be
                             // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
-                            mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
-                                    mOptions, mStartActivity.appTimeTracker,
+                            mTargetStack.moveTaskToFrontLocked(intentTask,
+                                    mNoAnimation, mOptions, mStartActivity.appTimeTracker,
                                     "bringToFrontInsteadOfAdjacentLaunch");
                         }
                         mMovedToFront = true;
@@ -1570,7 +1570,7 @@
                         // Target and computed stacks are on different displays and we've
                         // found a matching task - move the existing instance to that display and
                         // move it to front.
-                        intentActivity.task.reparent(launchStack.mStackId, ON_TOP,
+                        intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP,
                                 REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
                                 "reparentToDisplay");
                         mMovedToFront = true;
@@ -1582,7 +1582,7 @@
                     intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
                             true /* taskSwitch */);
                 }
-                updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
+                updateTaskReturnToType(intentActivity.getTask(), mLaunchFlags, focusStack);
             }
         }
         if (!mMovedToFront && mDoResume) {
@@ -1591,7 +1591,7 @@
             mTargetStack.moveToFront("intentActivityFound");
         }
 
-        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
+        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID,
                 mTargetStack.mStackId);
 
         // If the caller has requested that the target task be reset, then do so.
@@ -1635,7 +1635,7 @@
             // launching another activity.
             // TODO(b/36119896):  We shouldn't trigger activity launches in this path since we are
             // already launching one.
-            final TaskRecord task = intentActivity.task;
+            final TaskRecord task = intentActivity.getTask();
             task.performClearTaskLocked();
             mReuseTask = task;
             mReuseTask.setIntent(mStartActivity);
@@ -1646,7 +1646,7 @@
             mMovedOtherTask = true;
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                 || mLaunchSingleInstance || mLaunchSingleTask) {
-            ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+            ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
                     mLaunchFlags);
             if (top == null) {
                 // A special case: we need to start the activity because it is not currently
@@ -1655,11 +1655,11 @@
                 mAddingToTask = true;
 
                 // We are no longer placing the activity in the task we previously thought we were.
-                mStartActivity.task = null;
+                mStartActivity.setTask(null);
                 // Now pretend like this activity is being started by the top of its task, so it
                 // is put in the right place.
                 mSourceRecord = intentActivity;
-                final TaskRecord task = mSourceRecord.task;
+                final TaskRecord task = mSourceRecord.getTask();
                 if (task != null && task.getStack() == null) {
                     // Target stack got cleared when we all activities were removed above.
                     // Go ahead and reset it.
@@ -1669,7 +1669,7 @@
                             !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
                 }
             }
-        } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+        } else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
             // In this case the top activity on the task is the same as the one being launched,
             // so we take that as a request to bring the task to the foreground. If the top
             // activity in the task is the root activity, deliver this new intent to it if it
@@ -1677,13 +1677,13 @@
             if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
                     && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
                 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
-                        intentActivity.task);
+                        intentActivity.getTask());
                 if (intentActivity.frontOfTask) {
-                    intentActivity.task.setIntent(mStartActivity);
+                    intentActivity.getTask().setIntent(mStartActivity);
                 }
                 intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                         mStartActivity.launchedFromPackage);
-            } else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) {
+            } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
                 // In this case we are launching the root activity of the task, but with a
                 // different intent. We should start a new instance on top.
                 mAddingToTask = true;
@@ -1696,13 +1696,13 @@
             // current task.
             mAddingToTask = true;
             mSourceRecord = intentActivity;
-        } else if (!intentActivity.task.rootWasReset) {
+        } else if (!intentActivity.getTask().rootWasReset) {
             // In this case we are launching into an existing task that has not yet been started
             // from its front door. The current task has been brought to the front. Ideally,
             // we'd probably like to place this new task at the bottom of its stack, but that's
             // a little hard to do with the current organization of the code so for now we'll
             // just drop it.
-            intentActivity.task.setIntent(mStartActivity);
+            intentActivity.getTask().setIntent(mStartActivity);
         }
     }
 
@@ -1736,11 +1736,11 @@
                     mService.resizeStack(
                             stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
                 } else {
-                    mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
+                    mStartActivity.getTask().updateOverrideConfiguration(mLaunchBounds);
                 }
             }
             if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                    + " in new task " + mStartActivity.task);
+                    + " in new task " + mStartActivity.getTask());
         } else {
             addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
         }
@@ -1749,7 +1749,7 @@
             mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
         }
 
-        if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+        if (mSupervisor.isLockTaskModeViolation(mStartActivity.getTask())) {
             Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
             return START_RETURN_LOCK_TASK_MODE_VIOLATION;
         }
@@ -1758,7 +1758,7 @@
             // If stack id is specified in activity options, usually it means that activity is
             // launched not from currently focused stack (e.g. from SysUI or from shell) - in
             // that case we check the target stack.
-            updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
+            updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags,
                     preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
         }
         if (mDoResume) {
@@ -1768,19 +1768,19 @@
     }
 
     private int setTaskFromSourceRecord() {
-        if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+        if (mSupervisor.isLockTaskModeViolation(mSourceRecord.getTask())) {
             Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
             return START_RETURN_LOCK_TASK_MODE_VIOLATION;
         }
 
-        final TaskRecord sourceTask = mSourceRecord.task;
+        final TaskRecord sourceTask = mSourceRecord.getTask();
         final ActivityStack sourceStack = mSourceRecord.getStack();
         // We only want to allow changing stack if the target task is not the top one,
         // otherwise we would move the launching task to the other side, rather than show
         // two side by side.
         final boolean moveStackAllowed = sourceStack.topTask() != sourceTask;
         if (moveStackAllowed) {
-            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.getTask(),
                     mOptions);
         }
 
@@ -1805,7 +1805,7 @@
             ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
             mKeepCurTransition = true;
             if (top != null) {
-                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
                 top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
                 // For paranoia, make sure we have correctly resumed the top activity.
                 mTargetStack.mLastPausedActivity = null;
@@ -1821,7 +1821,7 @@
             // stack if so.
             final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
             if (top != null) {
-                final TaskRecord task = top.task;
+                final TaskRecord task = top.getTask();
                 task.moveActivityToFrontLocked(top);
                 top.updateOptionsLocked(mOptions);
                 ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
@@ -1838,7 +1838,7 @@
         // the same task as the one that is starting it.
         addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord");
         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+                + " in existing task " + mStartActivity.getTask() + " from source " + mSourceRecord);
         return START_SUCCESS;
     }
 
@@ -1861,7 +1861,7 @@
                     || mLaunchSingleTop || mLaunchSingleTask) {
                 mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions,
                         mStartActivity.appTimeTracker, "inTaskToFront");
-                ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+                ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
                 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                     // We don't need to start a new activity, and the client said not to do
                     // anything if that is the case, so this is it!
@@ -1901,7 +1901,7 @@
 
         addOrReparentStartingActivity(mInTask, "setTaskFromInTask");
         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                + " in explicit task " + mStartActivity.task);
+                + " in explicit task " + mStartActivity.getTask());
 
         return START_SUCCESS;
     }
@@ -1913,17 +1913,17 @@
             mTargetStack.moveToFront("addingToTopTask");
         }
         final ActivityRecord prev = mTargetStack.topActivity();
-        final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
+        final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
                 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
                 mIntent, null, null, true, mStartActivity.mActivityType);
         addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
         mTargetStack.positionChildWindowContainerAtTop(task);
         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                + " in new guessed " + mStartActivity.task);
+                + " in new guessed " + mStartActivity.getTask());
     }
 
     private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
-        if (mStartActivity.task == null || mStartActivity.task == parent) {
+        if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
             parent.addActivityToTop(mStartActivity);
         } else {
             mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason);
@@ -1973,7 +1973,7 @@
 
     private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
             int launchFlags, ActivityOptions aOptions) {
-        final TaskRecord task = r.task;
+        final TaskRecord task = r.getTask();
         ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
         if (stack != null) {
             return stack;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 21c131c..ba72dcf 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -98,6 +98,7 @@
 
 
     AppErrors(Context context, ActivityManagerService service) {
+        context.assertRuntimeOverlayThemable();
         mService = service;
         mContext = context;
     }
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index 5f7f67a..347a357 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -34,6 +34,7 @@
 
     public BaseErrorDialog(Context context) {
         super(context, com.android.internal.R.style.Theme_Dialog_AppError);
+        context.assertRuntimeOverlayThemable();
 
         getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
diff --git a/services/core/java/com/android/server/am/PersistentConnection.java b/services/core/java/com/android/server/am/PersistentConnection.java
new file mode 100644
index 0000000..c34c097
--- /dev/null
+++ b/services/core/java/com/android/server/am/PersistentConnection.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Connects to a given service component on a given user.
+ *
+ * - Call {@link #connect()} to create a connection.
+ * - Call {@link #disconnect()} to disconnect.  Make sure to disconnect when the user stops.
+ *
+ * Add onConnected/onDisconnected callbacks as needed.
+ */
+public abstract class PersistentConnection<T> {
+    private final Object mLock = new Object();
+
+    private final String mTag;
+    private final Context mContext;
+    private final Handler mHandler;
+    private final int mUserId;
+    private final ComponentName mComponentName;
+
+    @GuardedBy("mLock")
+    private boolean mStarted;
+
+    @GuardedBy("mLock")
+    private boolean mIsConnected;
+
+    @GuardedBy("mLock")
+    private T mService;
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                Slog.i(mTag, "Connected: " + mComponentName.flattenToShortString()
+                        + " u" + mUserId);
+
+                mIsConnected = true;
+                mService = asInterface(service);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (mLock) {
+                Slog.i(mTag, "Disconnected: " + mComponentName.flattenToShortString()
+                        + " u" + mUserId);
+
+                cleanUpConnectionLocked();
+            }
+        }
+    };
+
+    public PersistentConnection(@NonNull String tag, @NonNull Context context,
+            @NonNull Handler handler, int userId, @NonNull ComponentName componentName) {
+        mTag = tag;
+        mContext = context;
+        mHandler = handler;
+        mUserId = userId;
+        mComponentName = componentName;
+    }
+
+    public final ComponentName getComponentName() {
+        return mComponentName;
+    }
+
+    /**
+     * @return whether connected.
+     */
+    public final boolean isConnected() {
+        synchronized (mLock) {
+            return mIsConnected;
+        }
+    }
+
+    /**
+     * @return the service binder interface.
+     */
+    public final T getServiceBinder() {
+        synchronized (mLock) {
+            return mService;
+        }
+    }
+
+    /**
+     * Connects to the service.
+     */
+    public final void connect() {
+        synchronized (mLock) {
+            if (mStarted) {
+                return;
+            }
+            mStarted = true;
+
+            final Intent service = new Intent().setComponent(mComponentName);
+
+            final boolean success = mContext.bindServiceAsUser(service, mServiceConnection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                    mHandler, UserHandle.of(mUserId));
+
+            if (!success) {
+                Slog.e(mTag, "Binding: " + service.getComponent() + " u" + mUserId
+                        + " failed.");
+            }
+        }
+    }
+
+    private void cleanUpConnectionLocked() {
+        mIsConnected = false;
+        mService = null;
+    }
+
+    /**
+     * Disconnect from the service.
+     */
+    public final void disconnect() {
+        synchronized (mLock) {
+            if (!mStarted) {
+                return;
+            }
+            Slog.i(mTag, "Stopping: " + mComponentName.flattenToShortString() + " u" + mUserId);
+            mStarted = false;
+            mContext.unbindService(mServiceConnection);
+
+            cleanUpConnectionLocked();
+        }
+    }
+
+    /** Must be implemented by a subclass to convert an {@link IBinder} to a stub. */
+    protected abstract T asInterface(IBinder binder);
+
+    public void dump(String prefix, PrintWriter pw) {
+        synchronized (mLock) {
+            pw.print(prefix);
+            pw.print(mComponentName.flattenToShortString());
+            pw.print(mStarted ? "  [started]" : "  [not started]");
+            pw.print(mIsConnected ? "  [connected]" : "  [not connected]");
+            pw.println();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 40effff..0dc6788 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -350,58 +350,58 @@
         String procState;
         switch (curProcState) {
             case ActivityManager.PROCESS_STATE_PERSISTENT:
-                procState = "P ";
+                procState = "PER ";
                 break;
             case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
-                procState = "PU";
+                procState = "PERU";
                 break;
             case ActivityManager.PROCESS_STATE_TOP:
-                procState = "T ";
+                procState = "TOP";
                 break;
             case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                procState = "SB";
+                procState = "BFGS";
                 break;
             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
-                procState = "SF";
+                procState = "FGS ";
                 break;
             case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
-                procState = "TS";
+                procState = "TPSL";
                 break;
             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
-                procState = "IF";
+                procState = "IMPF";
                 break;
             case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
-                procState = "IB";
+                procState = "IMPB";
                 break;
             case ActivityManager.PROCESS_STATE_BACKUP:
-                procState = "BU";
+                procState = "BKUP";
                 break;
             case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
-                procState = "HW";
+                procState = "HVY ";
                 break;
             case ActivityManager.PROCESS_STATE_SERVICE:
-                procState = "S ";
+                procState = "SVC ";
                 break;
             case ActivityManager.PROCESS_STATE_RECEIVER:
-                procState = "R ";
+                procState = "RCVR";
                 break;
             case ActivityManager.PROCESS_STATE_HOME:
-                procState = "HO";
+                procState = "HOME";
                 break;
             case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
-                procState = "LA";
+                procState = "LAST";
                 break;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-                procState = "CA";
+                procState = "CAC ";
                 break;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                procState = "Ca";
+                procState = "CACC";
                 break;
             case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                procState = "CE";
+                procState = "CEM ";
                 break;
             case ActivityManager.PROCESS_STATE_NONEXISTENT:
-                procState = "N ";
+                procState = "NONE";
                 break;
             default:
                 procState = "??";
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 2d27204..3c5c5fd 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -287,7 +287,9 @@
                 pw.print(" setSchedGroup="); pw.print(setSchedGroup);
                 pw.print(" systemNoUi="); pw.print(systemNoUi);
                 pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
-        pw.print(prefix); pw.print("vrThreadTid="); pw.print(vrThreadTid);
+        if (vrThreadTid != 0) {
+            pw.print(prefix); pw.print("vrThreadTid="); pw.println(vrThreadTid);
+        }
         pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
                 pw.print(" repProcState="); pw.print(repProcState);
                 pw.print(" pssProcState="); pw.print(pssProcState);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 6a13d36..f45a8cc 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -41,6 +41,7 @@
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -104,13 +105,29 @@
      * @param userId the user Id
      */
     void loadUserRecentsLocked(int userId) {
-        if (!mUsersWithRecentsLoaded.get(userId)) {
-            // Load the task ids if not loaded.
-            loadPersistedTaskIdsForUserLocked(userId);
-            Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-            addAll(mTaskPersister.restoreTasksForUserLocked(userId));
-            cleanupLocked(userId);
-            mUsersWithRecentsLoaded.put(userId, true);
+        if (mUsersWithRecentsLoaded.get(userId)) {
+            return;
+        }
+
+        // Load the task ids if not loaded.
+        loadPersistedTaskIdsForUserLocked(userId);
+
+        // Check if any tasks are added before recents is loaded
+        final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
+        for (final TaskRecord task : this) {
+            if (task.userId == userId && shouldPersistTaskLocked(task)) {
+                preaddedTasks.put(task.taskId, true);
+            }
+        }
+
+        Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
+        addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
+        cleanupLocked(userId);
+        mUsersWithRecentsLoaded.put(userId, true);
+
+        // If we have tasks added before loading recents, we need to update persistent task IDs.
+        if (preaddedTasks.size() != 0) {
+            syncPersistentTaskIdsLocked();
         }
     }
 
@@ -149,8 +166,7 @@
         }
         for (int i = size() - 1; i >= 0; i--) {
             final TaskRecord task = get(i);
-            final ActivityStack stack = task.getStack();
-            if (task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack())) {
+            if (shouldPersistTaskLocked(task)) {
                 // Set of persisted taskIds for task.userId should not be null here
                 // TODO Investigate why it can happen. For now initialize with an empty set
                 if (mPersistedTaskIds.get(task.userId) == null) {
@@ -163,6 +179,10 @@
         }
     }
 
+    private static boolean shouldPersistTaskLocked(TaskRecord task) {
+        final ActivityStack<?> stack = task.getStack();
+        return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack());
+    }
 
     void onSystemReadyLocked() {
         clear();
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 9deabb3..04b09c7 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -78,9 +78,8 @@
     /** Special value for mWriteTime to mean don't wait, just write */
     private static final long FLUSH_QUEUE = -1;
 
-    private static final String RECENTS_FILENAME = "_task";
     private static final String TASKS_DIRNAME = "recent_tasks";
-    private static final String TASK_EXTENSION = ".xml";
+    private static final String TASK_FILENAME_SUFFIX = "_task.xml";
     private static final String IMAGES_DIRNAME = "recent_images";
     private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
     static final String IMAGE_EXTENSION = ".png";
@@ -412,7 +411,7 @@
         return null;
     }
 
-    List<TaskRecord> restoreTasksForUserLocked(final int userId) {
+    List<TaskRecord> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
         final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
@@ -430,6 +429,22 @@
                 Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                         + ", taskFile=" + taskFile.getName());
             }
+
+            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
+                continue;
+            }
+            try {
+                final int taskId = Integer.parseInt(taskFile.getName().substring(
+                        0, taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
+                if (preaddedTasks.get(taskId, false)) {
+                    Slog.w(TAG, "Task #" + taskId + " has already been created so we don't restore"
+                            + " again");
+                    continue;
+                }
+            } catch (NumberFormatException e) {
+                continue;
+            }
+
             BufferedReader reader = null;
             boolean deleteFile = false;
             try {
@@ -744,13 +759,11 @@
                         try {
                             atomicFile = new AtomicFile(new File(
                                     getUserTasksDir(task.userId),
-                                    String.valueOf(task.taskId) + RECENTS_FILENAME
-                                    + TASK_EXTENSION));
+                                    String.valueOf(task.taskId) + TASK_FILENAME_SUFFIX));
                             file = atomicFile.startWrite();
                             file.write(stringWriter.toString().getBytes());
                             file.write('\n');
                             atomicFile.finishWrite(file);
-
                         } catch (IOException e) {
                             if (file != null) {
                                 atomicFile.failWrite(file);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 27a2461..c7f20b9f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -660,17 +660,6 @@
             // we are coming from in WM before we reparent because it became empty.
             mWindowContainerController.reparent(toStack.getWindowContainerController(), position);
 
-            // Reset the resumed activity on the previous stack
-            if (wasResumed) {
-                sourceStack.mResumedActivity = null;
-            }
-
-            // Reset the paused activity on the previous stack
-            if (wasPaused) {
-                sourceStack.mPausingActivity = null;
-                sourceStack.removeTimeoutsForActivityLocked(r);
-            }
-
             // Move the task
             sourceStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING);
             toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
@@ -1212,14 +1201,13 @@
      * be in the current task or unparented to any task.
      */
     void addActivityAtIndex(int index, ActivityRecord r) {
-        if (r.task != null && r.task != this) {
+        TaskRecord task = r.getTask();
+        if (task != null && task != this) {
             throw new IllegalArgumentException("Can not add r=" + " to task=" + this
-                    + " current parent=" + r.task);
+                    + " current parent=" + task);
         }
-        // TODO(b/36505427): Maybe make task private to ActivityRecord so we can also do
-        // onParentChanged() within the setter?
-        r.task = this;
-        r.onParentChanged();
+
+        r.setTask(this);
 
         // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
         if (!mActivities.remove(r) && r.fullscreen) {
@@ -1274,15 +1262,21 @@
     }
 
     /**
-     * @return true if this was the last activity in the task
+     * Removes the specified activity from this task.
+     * @param r The {@link ActivityRecord} to remove.
+     * @return true if this was the last activity in the task.
      */
     boolean removeActivity(ActivityRecord r) {
-        if (r.task != this) {
+        return removeActivity(r, false /*reparenting*/);
+    }
+
+    boolean removeActivity(ActivityRecord r, boolean reparenting) {
+        if (r.getTask() != this) {
             throw new IllegalArgumentException(
                     "Activity=" + r + " does not belong to task=" + this);
         }
 
-        r.task = null;
+        r.setTask(null /*task*/, reparenting);
 
         if (mActivities.remove(r) && r.fullscreen) {
             // Was previously in list.
@@ -1437,7 +1431,7 @@
     TaskThumbnail getTaskThumbnailLocked() {
         if (mStack != null) {
             final ActivityRecord resumedActivity = mStack.mResumedActivity;
-            if (resumedActivity != null && resumedActivity.task == this) {
+            if (resumedActivity != null && resumedActivity.getTask() == this) {
                 final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
                 setLastThumbnailLocked(thumbnail);
             }
@@ -1619,6 +1613,9 @@
             String iconFilename = null;
             int colorPrimary = 0;
             int colorBackground = 0;
+            int statusBarColor = 0;
+            int navigationBarColor = 0;
+            boolean topActivity = true;
             for (--activityNdx; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = mActivities.get(activityNdx);
                 if (r.taskDescription != null) {
@@ -1631,13 +1628,16 @@
                     if (colorPrimary == 0) {
                         colorPrimary = r.taskDescription.getPrimaryColor();
                     }
-                    if (colorBackground == 0) {
+                    if (topActivity) {
                         colorBackground = r.taskDescription.getBackgroundColor();
+                        statusBarColor = r.taskDescription.getStatusBarColor();
+                        navigationBarColor = r.taskDescription.getNavigationBarColor();
                     }
                 }
+                topActivity = false;
             }
             lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
-                    colorBackground);
+                    colorBackground, statusBarColor, navigationBarColor);
             if (mWindowContainerController != null) {
                 mWindowContainerController.setTaskDescription(lastTaskDescription);
             }
@@ -1953,7 +1953,7 @@
         task.updateOverrideConfiguration(bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
-            activities.get(activityNdx).task = task;
+            activities.get(activityNdx).setTask(task);
         }
 
         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 70e56b0..c11f531 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -55,6 +55,7 @@
 import android.hardware.usb.UsbManager;
 import android.media.AudioAttributes;
 import android.media.AudioDevicePort;
+import android.media.AudioFocusInfo;
 import android.media.AudioSystem;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -5634,8 +5635,9 @@
                 clientId, callingPackageName, flags);
     }
 
-    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
-        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
+    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
+            String callingPackageName) {
+        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
     }
 
     public void unregisterAudioFocusClient(String clientId) {
@@ -5650,6 +5652,7 @@
         return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
     }
 
+    //==========================================================================================
     private boolean readCameraSoundForced() {
         return SystemProperties.getBoolean("audio.camerasound.force", false) ||
                 mContext.getResources().getBoolean(
@@ -6430,7 +6433,7 @@
     // Audio policy management
     //==========================================================================================
     public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
-            boolean hasFocusListener) {
+            boolean hasFocusListener, boolean isFocusPolicy) {
         AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
 
         if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
@@ -6452,7 +6455,8 @@
                     Slog.e(TAG, "Cannot re-register policy");
                     return null;
                 }
-                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
+                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
+                        isFocusPolicy);
                 pcb.asBinder().linkToDeath(app, 0/*flags*/);
                 regId = app.getRegistrationId();
                 mAudioPolicies.put(pcb.asBinder(), app);
@@ -6650,15 +6654,21 @@
          * is handling ducking for audio focus.
          */
         int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
+        boolean mIsFocusPolicy = false;
 
         AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
-                boolean hasFocusListener) {
+                boolean hasFocusListener, boolean isFocusPolicy) {
             super(config);
             setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
             mPolicyCallback = token;
             mHasFocusListener = hasFocusListener;
             if (mHasFocusListener) {
                 mMediaFocusControl.addFocusFollower(mPolicyCallback);
+                // can only ever be true if there is a focus listener
+                if (isFocusPolicy) {
+                    mIsFocusPolicy = true;
+                    mMediaFocusControl.setFocusPolicy(mPolicyCallback);
+                }
             }
             connectMixes();
         }
@@ -6676,6 +6686,9 @@
         }
 
         void release() {
+            if (mIsFocusPolicy) {
+                mMediaFocusControl.unsetFocusPolicy(mPolicyCallback);
+            }
             if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
                 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
             }
@@ -6690,6 +6703,22 @@
         }
     };
 
+    //======================
+    // Audio policy: focus
+    //======================
+    /**  */
+    public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
+        synchronized (mAudioPolicies) {
+            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
+                throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
+            }
+            return mMediaFocusControl.dispatchFocusChange(afi, focusChange);
+        }
+    }
+
+    //======================
+    // misc
+    //======================
     private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
             new HashMap<IBinder, AudioPolicyProxy>();
     private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 5275c05..bcaa295 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -33,7 +33,7 @@
  * @hide
  * Class to handle all the information about a user of audio focus. The lifecycle of each
  * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
- * stack to its release.
+ * stack, or the map of focus owners for an external focus policy, to its release.
  */
 public class FocusRequester {
 
@@ -101,6 +101,21 @@
         mFocusController = ctlr;
     }
 
+    FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl,
+             IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr) {
+        mAttributes = afi.getAttributes();
+        mClientId = afi.getClientId();
+        mPackageName = afi.getPackageName();
+        mCallingUid = afi.getClientUid();
+        mFocusGainRequest = afi.getGainRequest();
+        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+        mGrantFlags = afi.getFlags();
+
+        mFocusDispatcher = afl;
+        mSourceRef = source;
+        mDeathHandler = hdlr;
+        mFocusController = ctlr;
+    }
 
     boolean hasSameClient(String otherClient) {
         try {
@@ -118,6 +133,10 @@
         return (mSourceRef != null) && mSourceRef.equals(ib);
     }
 
+    boolean hasSameDispatcher(IAudioFocusDispatcher fd) {
+        return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd);
+    }
+
     boolean hasSamePackage(String pack) {
         try {
             return mPackageName.compareTo(pack) == 0;
@@ -369,6 +388,35 @@
         }
     }
 
+    int dispatchFocusChange(int focusChange) {
+        if (mFocusDispatcher == null) {
+            if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: no focus dispatcher"); }
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+        if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
+            if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); }
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        } else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
+                || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
+                || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
+                || focusChange == AudioManager.AUDIOFOCUS_GAIN)
+                && (mFocusGainRequest != focusChange)){
+            Log.w(TAG, "focus gain was requested with " + mFocusGainRequest
+                    + ", dispatching " + focusChange);
+        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+                || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
+                || focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+            mFocusLossReceived = focusChange;
+        }
+        try {
+            mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId);
+        } catch (android.os.RemoteException e) {
+            Log.v(TAG, "dispatchFocusChange: error talking to focus listener", e);
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
     AudioFocusInfo toAudioFocusInfo() {
         return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName,
                 mFocusGainRequest, mFocusLossReceived, mGrantFlags);
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index b3f1548..821e78a 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.audio;
 
+import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.media.AudioAttributes;
@@ -23,6 +24,7 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.IAudioFocusDispatcher;
+import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.os.Binder;
 import android.os.IBinder;
@@ -32,7 +34,10 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.Stack;
 import java.text.DateFormat;
 
@@ -43,6 +48,7 @@
 public class MediaFocusControl implements PlayerFocusEnforcer {
 
     private static final String TAG = "MediaFocusControl";
+    static final boolean DEBUG = false;
 
     /**
      * set to true so the framework enforces ducking itself, without communicating to apps
@@ -155,6 +161,13 @@
             while(stackIterator.hasNext()) {
                 stackIterator.next().dump(pw);
             }
+            pw.println("\n");
+            if (mFocusPolicy == null) {
+                pw.println("No external focus policy\n");
+            } else {
+                pw.println("External focus policy: "+ mFocusPolicy + ", focus owners:\n");
+                dumpExtFocusPolicyFocusOwners(pw);
+            }
         }
         pw.println("\n");
         pw.println(" Notify on duck:  " + mNotifyFocusOwnerOnDuck + "\n");
@@ -234,6 +247,31 @@
     }
 
     /**
+     * Helper function for external focus policy:
+     * Called synchronized on mAudioFocusLock
+     * Remove focus listeners from the list of potential focus owners for a particular client when
+     * it has died.
+     */
+    private void removeFocusEntryForExtPolicy(IBinder cb) {
+        if (mFocusOwnersForFocusPolicy.isEmpty()) {
+            return;
+        }
+        boolean released = false;
+        final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
+        final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
+        while (ownerIterator.hasNext()) {
+            final Entry<String, FocusRequester> owner = ownerIterator.next();
+            final FocusRequester fr = owner.getValue();
+            if (fr.hasSameBinder(cb)) {
+                ownerIterator.remove();
+                fr.release();
+                notifyExtFocusPolicyFocusAbandon_syncAf(fr.toAudioFocusInfo());
+                break;
+            }
+        }
+    }
+
+    /**
      * Helper function:
      * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
      * The implementation guarantees that a state where focus cannot be immediately reassigned
@@ -297,7 +335,11 @@
 
         public void binderDied() {
             synchronized(mAudioFocusLock) {
-                removeFocusStackEntryOnDeath(mCb);
+                if (mFocusPolicy != null) {
+                    removeFocusEntryForExtPolicy(mCb);
+                } else {
+                    removeFocusStackEntryOnDeath(mCb);
+                }
             }
         }
     }
@@ -353,6 +395,34 @@
         }
     }
 
+    private IAudioPolicyCallback mFocusPolicy = null;
+
+    // Since we don't have a stack of focus owners when using an external focus policy, we keep
+    // track of all the focus requesters in this map, with their clientId as the key. This is
+    // used both for focus dispatch and death handling
+    private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy =
+            new HashMap<String, FocusRequester>();
+
+    void setFocusPolicy(IAudioPolicyCallback policy) {
+        if (policy == null) {
+            return;
+        }
+        synchronized (mAudioFocusLock) {
+            mFocusPolicy = policy;
+        }
+    }
+
+    void unsetFocusPolicy(IAudioPolicyCallback policy) {
+        if (policy == null) {
+            return;
+        }
+        synchronized (mAudioFocusLock) {
+            if (mFocusPolicy == policy) {
+                mFocusPolicy = null;
+            }
+        }
+    }
+
     /**
      * @param pcb non null
      */
@@ -409,6 +479,100 @@
         }
     }
 
+    /**
+     * Called synchronized on mAudioFocusLock
+     * @param afi
+     * @param requestResult
+     * @return true if the external audio focus policy (if any) is handling the focus request
+     */
+    boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult,
+            IAudioFocusDispatcher fd, IBinder cb) {
+        if (mFocusPolicy == null) {
+            return false;
+        }
+        if (DEBUG) {
+            Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
+            + " dispatcher=" + fd);
+        }
+        final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+        if (existingFr != null) {
+            if (!existingFr.hasSameDispatcher(fd)) {
+                existingFr.release();
+                final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
+                mFocusOwnersForFocusPolicy.put(afi.getClientId(),
+                        new FocusRequester(afi, fd, cb, hdlr, this));
+            }
+        } else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
+                 || requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+            // new focus (future) focus owner to keep track of
+            final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
+            mFocusOwnersForFocusPolicy.put(afi.getClientId(),
+                    new FocusRequester(afi, fd, cb, hdlr, this));
+        }
+        try {
+            //oneway
+            mFocusPolicy.notifyAudioFocusRequest(afi, requestResult);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
+                    + mFocusPolicy.asBinder(), e);
+        }
+        return true;
+    }
+
+    /**
+     * Called synchronized on mAudioFocusLock
+     * @param afi
+     * @param requestResult
+     * @return true if the external audio focus policy (if any) is handling the focus request
+     */
+    boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) {
+        if (mFocusPolicy == null) {
+            return false;
+        }
+        final FocusRequester fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
+        if (fr != null) {
+            fr.release();
+        }
+        try {
+            //oneway
+            mFocusPolicy.notifyAudioFocusAbandon(afi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Can't call notifyAudioFocusAbandon() on IAudioPolicyCallback "
+                    + mFocusPolicy.asBinder(), e);
+        }
+        return true;
+    }
+
+    /** see AudioManager.dispatchFocusChange(AudioFocusInfo afi, int focusChange, AudioPolicy ap) */
+    int dispatchFocusChange(AudioFocusInfo afi, int focusChange) {
+        if (DEBUG) {
+            Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client="
+                    + afi.getClientId());
+        }
+        synchronized (mAudioFocusLock) {
+            if (mFocusPolicy == null) {
+                if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+            final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+            if (fr == null) {
+                if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+            return fr.dispatchFocusChange(focusChange);
+        }
+    }
+
+    private void dumpExtFocusPolicyFocusOwners(PrintWriter pw) {
+        final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
+        final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
+        while (ownerIterator.hasNext()) {
+            final Entry<String, FocusRequester> owner = ownerIterator.next();
+            final FocusRequester fr = owner.getValue();
+            fr.dump(pw);
+        }
+    }
+
     protected int getCurrentAudioFocus() {
         synchronized(mAudioFocusLock) {
             if (mFocusStack.empty()) {
@@ -487,10 +651,23 @@
                     & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
             if (enteringRingOrCall) { mRingOrCallActive = true; }
 
+            final AudioFocusInfo afiForExtPolicy;
+            if (mFocusPolicy != null) {
+                // construct AudioFocusInfo as it will be communicated to audio focus policy
+                afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(),
+                        clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
+                        flags);
+            } else {
+                afiForExtPolicy = null;
+            }
+
+            // handle delayed focus
             boolean focusGrantDelayed = false;
             if (!canReassignAudioFocus()) {
                 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                    final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                    notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb);
+                    return result;
                 } else {
                     // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
                     // granted right now, so the requester will be inserted in the focus stack
@@ -499,6 +676,14 @@
                 }
             }
 
+            // external focus policy: delay request for focus gain?
+            final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+            if (notifyExtFocusPolicyFocusRequest_syncAf(
+                    afiForExtPolicy, resultWithExtPolicy, fd, cb)) {
+                // stop handling focus request here as it is handled by external audio focus policy
+                return resultWithExtPolicy;
+            }
+
             // handle the potential premature death of the new holder of the focus
             // (premature death == death before abandoning focus)
             // Register for client death notification
@@ -569,7 +754,8 @@
     /**
      * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
      * */
-    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
+    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa,
+            String callingPackageName) {
         // AudioAttributes are currently ignored, to be used for zones
         Log.i(TAG, " AudioFocus  abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
                 + "/" + Binder.getCallingPid()
@@ -577,6 +763,16 @@
         try {
             // this will take care of notifying the new focus owner if needed
             synchronized(mAudioFocusLock) {
+                // external focus policy?
+                if (mFocusPolicy != null) {
+                    final AudioFocusInfo afi = new AudioFocusInfo(aa, Binder.getCallingUid(),
+                            clientId, callingPackageName, 0 /*gainRequest*/, 0 /*lossReceived*/,
+                            0 /*flags*/);
+                    if (notifyExtFocusPolicyFocusAbandon_syncAf(afi)) {
+                        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                    }
+                }
+
                 boolean exitingRingOrCall = mRingOrCallActive
                         & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
                 if (exitingRingOrCall) { mRingOrCallActive = false; }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a1a7437..ddd918f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -339,6 +339,18 @@
         }
     }
 
+    /**
+     * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
+     */
+    private void getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo) {
+        synchronized (mSyncRoot) {
+            final LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null) {
+                display.getNonOverrideDisplayInfoLocked(outInfo);
+            }
+        }
+    }
+
     private void performTraversalInTransactionFromWindowManagerInternal() {
         synchronized (mSyncRoot) {
             if (!mPendingTraversal) {
@@ -1663,6 +1675,11 @@
         }
 
         @Override
+        public void getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo) {
+            getNonOverrideDisplayInfoInternal(displayId, outInfo);
+        }
+
+        @Override
         public void performTraversalInTransactionFromWindowManager() {
             performTraversalInTransactionFromWindowManagerInternal();
         }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index a947b41..addad0b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.graphics.Rect;
+import android.hardware.display.DisplayManagerInternal;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
@@ -62,7 +63,18 @@
 
     private final int mDisplayId;
     private final int mLayerStack;
-    private DisplayInfo mOverrideDisplayInfo; // set by the window manager
+    /**
+     * Override information set by the window manager. Will be reported instead of {@link #mInfo}
+     * if not null.
+     * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo)
+     * @see #getDisplayInfoLocked()
+     */
+    private DisplayInfo mOverrideDisplayInfo;
+    /**
+     * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if
+     * needs to be updated.
+     * @see #getDisplayInfoLocked()
+     */
     private DisplayInfo mInfo;
 
     // The display device that this logical display is based on and which
@@ -142,6 +154,13 @@
     }
 
     /**
+     * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
+     */
+    void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) {
+        outInfo.copyFrom(mBaseDisplayInfo);
+    }
+
+    /**
      * Sets overridden logical display information from the window manager.
      * This method can be used to adjust application insets, rotation, and other
      * properties that the window manager takes care of.
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 9e4432d..dc2ebb4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -27,4 +27,15 @@
      * Resets all policies associated with a given user.
      */
     public abstract void resetUserState(int userId);
+
+    /**
+     * @return true if the given uid is restricted from doing networking on metered networks.
+     */
+    public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
+
+    /**
+     * @return true if networking is blocked on the given interface for the given uid according
+     * to current networking policies.
+     */
+    public abstract boolean isUidNetworkingBlocked(int uid, String ifname);
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 4e1166b..02e106e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -248,8 +248,8 @@
  */
 public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     static final String TAG = "NetworkPolicy";
-    private static final boolean LOGD = false;
-    private static final boolean LOGV = false;
+    private static final boolean LOGD = true; // UNDO
+    private static final boolean LOGV = true; // UNDO
 
     private static final int VERSION_INIT = 1;
     private static final int VERSION_ADDED_SNOOZE = 2;
@@ -428,9 +428,6 @@
     @GuardedBy("mUidRulesFirstLock")
     final SparseIntArray mUidState = new SparseIntArray();
 
-    /** Higher priority listener before general event dispatch */
-    private INetworkPolicyListener mConnectivityListener;
-
     private final RemoteCallbackList<INetworkPolicyListener>
             mListeners = new RemoteCallbackList<>();
 
@@ -2237,15 +2234,6 @@
     }
 
     @Override
-    public void setConnectivityListener(INetworkPolicyListener listener) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        if (mConnectivityListener != null) {
-            throw new IllegalStateException("Connectivity listener already registered");
-        }
-        mConnectivityListener = listener;
-    }
-
-    @Override
     public void registerListener(INetworkPolicyListener listener) {
         // TODO: create permission for observing network policy
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -3556,7 +3544,6 @@
                 case MSG_RULES_CHANGED: {
                     final int uid = msg.arg1;
                     final int uidRules = msg.arg2;
-                    dispatchUidRulesChanged(mConnectivityListener, uid, uidRules);
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -3567,7 +3554,6 @@
                 }
                 case MSG_METERED_IFACES_CHANGED: {
                     final String[] meteredIfaces = (String[]) msg.obj;
-                    dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces);
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -3598,7 +3584,6 @@
                 }
                 case MSG_RESTRICT_BACKGROUND_CHANGED: {
                     final boolean restrictBackground = msg.arg1 != 0;
-                    dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground);
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -3616,7 +3601,6 @@
                     final int policy = msg.arg2;
                     final Boolean notifyApp = (Boolean) msg.obj;
                     // First notify internal listeners...
-                    dispatchUidPoliciesChanged(mConnectivityListener, uid, policy);
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -4049,6 +4033,74 @@
                 }
             }
         }
+
+        /**
+         * @return true if the given uid is restricted from doing networking on metered networks.
+         */
+        @Override
+        public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+            final int uidRules;
+            final boolean isBackgroundRestricted;
+            synchronized (mUidRulesFirstLock) {
+                uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+                isBackgroundRestricted = mRestrictBackground;
+            }
+            return isBackgroundRestricted
+                    && !hasRule(uidRules, RULE_ALLOW_METERED)
+                    && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
+        }
+
+        /**
+         * @return true if networking is blocked on the given interface for the given uid according
+         * to current networking policies.
+         */
+        @Override
+        public boolean isUidNetworkingBlocked(int uid, String ifname) {
+            final int uidRules;
+            final boolean isBackgroundRestricted;
+            final boolean isNetworkMetered;
+            synchronized (mUidRulesFirstLock) {
+                uidRules = mUidRules.get(uid, RULE_NONE);
+                isBackgroundRestricted = mRestrictBackground;
+                synchronized (mNetworkPoliciesSecondLock) {
+                    isNetworkMetered = mMeteredIfaces.contains(ifname);
+                }
+            }
+            if (hasRule(uidRules, RULE_REJECT_ALL)) {
+                if (LOGV) logUidStatus(uid, "blocked by power restrictions");
+                return true;
+            }
+            if (!isNetworkMetered) {
+                if (LOGV) logUidStatus(uid, "allowed on unmetered network");
+                return false;
+            }
+            if (hasRule(uidRules, RULE_REJECT_METERED)) {
+                if (LOGV) logUidStatus(uid, "blacklisted on metered network");
+                return true;
+            }
+            if (hasRule(uidRules, RULE_ALLOW_METERED)) {
+                if (LOGV) logUidStatus(uid, "whitelisted on metered network");
+                return false;
+            }
+            if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
+                if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
+                return false;
+            }
+            if (isBackgroundRestricted) {
+                if (LOGV) logUidStatus(uid, "blocked when background is restricted");
+                return true;
+            }
+            if (LOGV) logUidStatus(uid, "allowed by default");
+            return false;
+        }
+    }
+
+    private static boolean hasRule(int uidRules, int rule) {
+        return (uidRules & rule) != 0;
+    }
+
+    private static void logUidStatus(int uid, String descr) {
+        Slog.d(TAG, String.format("uid %d is %s", uid, descr));
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 0b40fc5..f79f6f4 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -242,18 +242,8 @@
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
                 if (callingUserInfo.isManagedProfile()) {
-
-                    // STOPSHIP Remove the whitelist.
-                    if ("com.google.android.talk".equals(callingPackage)
-                            || "com.google.android.quicksearchbox".equals(callingPackage)
-                            || "com.google.android.googlequicksearchbox".equals(callingPackage)
-                            ) {
-                        return false;
-                    }
-                    // STOPSHIP Change it to 'e'.
-                    Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile "
+                    Slog.w(TAG, message + " by " + callingPackage + " for another profile "
                             + targetUserId + " from " + callingUserId);
-
                     return false;
                 }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5a54917..0ad3e59 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -842,11 +842,11 @@
 
     /** The service connection to the ephemeral resolver */
     final EphemeralResolverConnection mInstantAppResolverConnection;
+    /** Component used to show resolver settings for Instant Apps */
+    final ComponentName mInstantAppResolverSettingsComponent;
 
     /** Component used to install ephemeral applications */
     ComponentName mInstantAppInstallerComponent;
-    /** Component used to show resolver settings for Instant Apps */
-    ComponentName mInstantAppResolverSettingsComponent;
     ActivityInfo mInstantAppInstallerActivity;
     final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
 
@@ -2385,6 +2385,10 @@
 
             final VersionInfo ver = mSettings.getInternalVersion();
             mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+            if (mIsUpgrade) {
+                logCriticalInfo(Log.INFO,
+                        "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
+            }
 
             // when upgrading from pre-M, promote system app permissions from install to runtime
             mPromoteSystemApps =
@@ -2803,11 +2807,13 @@
                 }
                 mInstantAppResolverConnection =
                         new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
+                mInstantAppResolverSettingsComponent =
+                        getEphemeralResolverSettingsLPr(ephemeralResolverComponent);
             } else {
                 mInstantAppResolverConnection = null;
+                mInstantAppResolverSettingsComponent = null;
             }
             updateInstantAppInstallerLocked();
-            mInstantAppResolverSettingsComponent = getEphemeralResolverSettingsLPr();
 
             // Read and update the usage of dex files.
             // Do this at the end of PM init so that all the packages have their
@@ -3115,35 +3121,18 @@
         }
     }
 
-    private @Nullable ComponentName getEphemeralResolverSettingsLPr() {
-        final Intent intent = new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS);
-        intent.addCategory(Intent.CATEGORY_DEFAULT);
-        final int resolveFlags =
-                MATCH_DIRECT_BOOT_AWARE
-                | MATCH_DIRECT_BOOT_UNAWARE
-                | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
-        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
-                resolveFlags, UserHandle.USER_SYSTEM);
-        Iterator<ResolveInfo> iter = matches.iterator();
-        while (iter.hasNext()) {
-            final ResolveInfo rInfo = iter.next();
-            final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
-            if (ps != null) {
-                final PermissionsState permissionsState = ps.getPermissionsState();
-                if (permissionsState.hasPermission(Manifest.permission.ACCESS_INSTANT_APPS, 0)) {
-                    continue;
-                }
-            }
-            iter.remove();
-        }
-        if (matches.size() == 0) {
+    private @Nullable ComponentName getEphemeralResolverSettingsLPr(
+            @NonNull ComponentName resolver) {
+        final Intent intent =  new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS)
+                .addCategory(Intent.CATEGORY_DEFAULT)
+                .setPackage(resolver.getPackageName());
+        final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null, resolveFlags,
+                UserHandle.USER_SYSTEM);
+        if (matches.isEmpty()) {
             return null;
-        } else if (matches.size() == 1) {
-            return matches.get(0).getComponentInfo().getComponentName();
-        } else {
-            throw new RuntimeException(
-                    "There must be at most one ephemeral resolver settings; found " + matches);
         }
+        return matches.get(0).getComponentInfo().getComponentName();
     }
 
     private void primeDomainVerificationsLPw(int userId) {
@@ -22163,7 +22152,10 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                mCloseGuard.warnIfOpen();
+                if (mCloseGuard != null) {
+                    mCloseGuard.warnIfOpen();
+                }
+
                 close();
             } finally {
                 super.finalize();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0a0ef58..7c89e1c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3421,6 +3421,11 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+        dumpNoCheck(fd, pw, args);
+    }
+
+    @VisibleForTesting
+    void dumpNoCheck(FileDescriptor fd, PrintWriter pw, String[] args) {
         boolean checkin = false;
         boolean clear = false;
         if (args != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b507df0..95fb5af 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2945,6 +2945,7 @@
                 }
                 mStatusBar = win;
                 mStatusBarController.setWindow(win);
+                setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
                 break;
             case TYPE_NAVIGATION_BAR:
                 mContext.enforceCallingOrSelfPermission(
@@ -3832,7 +3833,7 @@
             mPendingKeyguardOccluded = occluded;
             mKeyguardOccludedChanged = true;
         } else {
-            setKeyguardOccludedLw(occluded);
+            setKeyguardOccludedLw(occluded, false /* force */);
         }
     }
 
@@ -3841,7 +3842,7 @@
             if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
                     + mPendingKeyguardOccluded);
             mKeyguardOccludedChanged = false;
-            if (setKeyguardOccludedLw(mPendingKeyguardOccluded)) {
+            if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */)) {
                 return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
             }
         }
@@ -5254,11 +5255,8 @@
             }
         }
 
-        // Don't allow snapshots to influence SystemUI visibility flags.
-        // TODO: Revisit this once SystemUI flags for snapshots are handled correctly
         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
-                && attrs.type < FIRST_SYSTEM_WINDOW
-                && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0;
+                && attrs.type < FIRST_SYSTEM_WINDOW;
         final int stackId = win.getStackId();
         if (mTopFullscreenOpaqueWindowState == null && visible) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
@@ -5475,23 +5473,27 @@
      *
      * @return Whether the flags have changed and we have to redo the layout.
      */
-    private boolean setKeyguardOccludedLw(boolean isOccluded) {
+    private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force) {
         if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
         boolean wasOccluded = mKeyguardOccluded;
         boolean showing = mKeyguardDelegate.isShowing();
         if (wasOccluded && !isOccluded && showing) {
             mKeyguardOccluded = false;
             mKeyguardDelegate.setOccluded(false, true /* animate */);
-            mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
-            if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
-                mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            if (mStatusBar != null) {
+                mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+                if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
+                    mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+                }
             }
             return true;
         } else if (!wasOccluded && isOccluded && showing) {
             mKeyguardOccluded = true;
             mKeyguardDelegate.setOccluded(true, false /* animate */);
-            mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
-            mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+            if (mStatusBar != null) {
+                mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+                mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+            }
             return true;
         } else if (wasOccluded != isOccluded) {
             mKeyguardOccluded = isOccluded;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9c4e700..a60dae7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2671,11 +2671,11 @@
             public void run() {
                 synchronized (this) {
                     if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
-                        ShutdownThread.rebootSafeMode(mContext, confirm);
+                        ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                     } else if (haltMode == HALT_MODE_REBOOT) {
-                        ShutdownThread.reboot(mContext, reason, confirm);
+                        ShutdownThread.reboot(getUiContext(), reason, confirm);
                     } else {
-                        ShutdownThread.shutdown(mContext, reason, confirm);
+                        ShutdownThread.shutdown(getUiContext(), reason, confirm);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 841e2a1..864e83e 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -79,7 +79,7 @@
     private static final int SHUTDOWN_VIBRATE_MS = 500;
 
     // state tracking
-    private static Object sIsStartedGuard = new Object();
+    private static final Object sIsStartedGuard = new Object();
     private static boolean sIsStarted = false;
 
     private static boolean mReboot;
@@ -121,7 +121,8 @@
      * state etc.  Must be called from a Looper thread in which its UI
      * is shown.
      *
-     * @param context Context used to display the shutdown progress dialog.
+     * @param context Context used to display the shutdown progress dialog. This must be a context
+     *                suitable for displaying UI (aka Themable).
      * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
      * @param confirm true if user confirmation is needed before shutting down.
      */
@@ -132,7 +133,11 @@
         shutdownInner(context, confirm);
     }
 
-    static void shutdownInner(final Context context, boolean confirm) {
+    private static void shutdownInner(final Context context, boolean confirm) {
+        // ShutdownThread is called from many places, so best to verify here that the context passed
+        // in is themed.
+        context.assertRuntimeOverlayThemable();
+
         // ensure that only one thread is trying to power down.
         // any additional calls are just returned
         synchronized (sIsStartedGuard) {
@@ -204,7 +209,8 @@
      * state etc.  Must be called from a Looper thread in which its UI
      * is shown.
      *
-     * @param context Context used to display the shutdown progress dialog.
+     * @param context Context used to display the shutdown progress dialog. This must be a context
+     *                suitable for displaying UI (aka Themable).
      * @param reason code to pass to the kernel (e.g. "recovery"), or null.
      * @param confirm true if user confirmation is needed before shutting down.
      */
@@ -220,7 +226,8 @@
      * Request a reboot into safe mode.  Must be called from a Looper thread in which its UI
      * is shown.
      *
-     * @param context Context used to display the shutdown progress dialog.
+     * @param context Context used to display the shutdown progress dialog. This must be a context
+     *                suitable for displaying UI (aka Themable).
      * @param confirm true if user confirmation is needed before shutting down.
      */
     public static void rebootSafeMode(final Context context, boolean confirm) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 212bd61..218d218 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.statusbar;
 
+import android.app.ActivityThread;
 import android.app.StatusBarManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -61,6 +62,7 @@
     private static final boolean SPEW = false;
 
     private final Context mContext;
+
     private final WindowManagerService mWindowManager;
     private Handler mHandler = new Handler();
     private NotificationDelegate mNotificationDelegate;
@@ -777,10 +779,12 @@
         long identity = Binder.clearCallingIdentity();
         try {
             mHandler.post(() -> {
+                // ShutdownThread displays UI, so give it a UI context.
+                Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
                 if (safeMode) {
-                    ShutdownThread.rebootSafeMode(mContext, false);
+                    ShutdownThread.rebootSafeMode(uiContext, false);
                 } else {
-                    ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false);
+                    ShutdownThread.reboot(uiContext, PowerManager.SHUTDOWN_USER_REQUESTED, false);
                 }
             });
         } finally {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f4f7e24..cc4c23d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -49,6 +49,7 @@
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.service.trust.TrustAgentService;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -580,16 +581,24 @@
         }
         PackageManager pm = mContext.getPackageManager();
         List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
+        ComponentName defaultAgent = getDefaultFactoryTrustAgent(mContext);
+        boolean shouldUseDefaultAgent = defaultAgent != null;
         ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            ComponentName componentName = getComponentName(resolveInfo);
-            int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
-            if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-                Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
-                        + "is not a system package.");
-                continue;
+
+        if (shouldUseDefaultAgent) {
+            discoveredAgents.add(defaultAgent);
+            Log.i(TAG, "Enabling " + defaultAgent + " because it is a default agent.");
+        } else { // A default agent is not set; perform regular trust agent discovery
+            for (ResolveInfo resolveInfo : resolveInfos) {
+                ComponentName componentName = getComponentName(resolveInfo);
+                int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
+                if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
+                            + "is not a system package.");
+                    continue;
+                }
+                discoveredAgents.add(componentName);
             }
-            discoveredAgents.add(componentName);
         }
 
         List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
@@ -601,6 +610,19 @@
                 Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
     }
 
+    /**
+     * Returns the {@link ComponentName} for the default trust agent, or {@code null} if there
+     * is no trust agent set.
+     */
+    private static ComponentName getDefaultFactoryTrustAgent(Context context) {
+        String defaultTrustAgent = context.getResources()
+            .getString(com.android.internal.R.string.config_defaultTrustAgent);
+        if (TextUtils.isEmpty(defaultTrustAgent)) {
+            return null;
+        }
+        return ComponentName.unflattenFromString(defaultTrustAgent);
+    }
+
     private List<ResolveInfo> resolveAllowedTrustAgents(PackageManager pm, int userId) {
         List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
                 PackageManager.GET_META_DATA |
diff --git a/services/core/java/com/android/server/tv/UinputBridge.java b/services/core/java/com/android/server/tv/UinputBridge.java
index f910332..1a984f9 100644
--- a/services/core/java/com/android/server/tv/UinputBridge.java
+++ b/services/core/java/com/android/server/tv/UinputBridge.java
@@ -63,7 +63,7 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mPtr != 0) {
+            if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
             }
             close(mToken);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 4b4be40..2bc3c5f 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -566,7 +566,7 @@
             return false;
         }
 
-        mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
+        mContainer.startingData = new SnapshotStartingData(mService, snapshot);
         scheduleAddStartingWindow();
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3c68e4f..4ebf1fc 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -180,11 +180,23 @@
     // Mapping from a token IBinder to a WindowToken object on this display.
     private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
 
+    // Initial display metrics.
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
     int mInitialDisplayDensity = 0;
+
+    /**
+     * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
+     * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
+     * @see WindowManagerService#setForcedDisplaySize(int, int, int)
+     */
     int mBaseDisplayWidth = 0;
     int mBaseDisplayHeight = 0;
+    /**
+     * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity}
+     * but can be set from Settings or via shell command "adb shell wm density".
+     * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int)
+     */
     int mBaseDisplayDensity = 0;
     boolean mDisplayScalingDisabled;
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -1497,8 +1509,12 @@
     }
 
     void updateDisplayInfo() {
+        // Check if display metrics changed and update base values if needed.
+        updateBaseDisplayMetricsIfNeeded();
+
         mDisplay.getDisplayInfo(mDisplayInfo);
         mDisplay.getMetrics(mDisplayMetrics);
+
         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
             mTaskStackContainers.get(i).updateDisplayInfo(null);
         }
@@ -1514,10 +1530,11 @@
             }
         }
 
-        mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
-        mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
-        mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
-        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+        updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
+                mDisplayInfo.logicalDensityDpi);
+        mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+        mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+        mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
     }
 
     void getLogicalDisplayRect(Rect out) {
@@ -1547,6 +1564,42 @@
         }
     }
 
+    /**
+     * If display metrics changed, overrides are not set and it's not just a rotation - update base
+     * values.
+     */
+    private void updateBaseDisplayMetricsIfNeeded() {
+        // Get real display metrics without overrides from WM.
+        mService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo);
+        final int orientation = mDisplayInfo.rotation;
+        final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
+        final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
+        final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
+        final int newDensity = mDisplayInfo.logicalDensityDpi;
+
+        final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
+                || mInitialDisplayHeight != newHeight
+                || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi;
+
+        if (displayMetricsChanged) {
+            // Check if display size or density is forced.
+            final boolean isDisplaySizeForced = mBaseDisplayWidth != mInitialDisplayWidth
+                    || mBaseDisplayHeight != mInitialDisplayHeight;
+            final boolean isDisplayDensityForced = mBaseDisplayDensity != mInitialDisplayDensity;
+
+            // If there is an override set for base values - use it, otherwise use new values.
+            updateBaseDisplayMetrics(isDisplaySizeForced ? mBaseDisplayWidth : newWidth,
+                    isDisplaySizeForced ? mBaseDisplayHeight : newHeight,
+                    isDisplayDensityForced ? mBaseDisplayDensity : newDensity);
+
+            // Real display metrics changed, so we should also update initial values.
+            mInitialDisplayWidth = newWidth;
+            mInitialDisplayHeight = newHeight;
+            mInitialDisplayDensity = newDensity;
+            mService.reconfigureDisplayLocked(this);
+        }
+    }
+
     /** Sets the maximum width the screen resolution can be */
     void setMaxUiWidth(int width) {
         if (DEBUG_DISPLAY) {
@@ -2867,7 +2920,11 @@
                     if (stack != null) {
                         stack.getBounds(frame);
                     }
-                } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
+
+                    // We want to screenshot with the exact bounds of the surface of the app. Thus,
+                    // intersect it with the frame.
+                    frame.intersect(w.mFrame);
+                }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
                     final Rect wf = w.mFrame;
                     final Rect cr = w.mContentInsets;
                     int left = wf.left + cr.left;
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index e73d4d2..35f35db 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.GraphicBuffer;
 import android.view.WindowManagerPolicy.StartingSurface;
 
@@ -25,9 +26,9 @@
 class SnapshotStartingData extends StartingData {
 
     private final WindowManagerService mService;
-    private final GraphicBuffer mSnapshot;
+    private final TaskSnapshot mSnapshot;
 
-    SnapshotStartingData(WindowManagerService service, GraphicBuffer snapshot) {
+    SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
         super(service);
         mService = service;
         mSnapshot = snapshot;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3ffb093..b816d81 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,15 +17,14 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -40,7 +39,6 @@
 import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b8d0b8c..48b01f4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -28,6 +28,7 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
 import android.os.Environment;
 import android.util.ArraySet;
 import android.view.WindowManagerPolicy.StartingSurface;
@@ -152,7 +153,7 @@
      * MANAGER LOCK WHEN CALLING THIS METHOD!
      */
     StartingSurface createStartingSurface(AppWindowToken token,
-            GraphicBuffer snapshot) {
+            TaskSnapshot snapshot) {
         return TaskSnapshotSurface.create(mService, token, snapshot);
     }
 
@@ -166,8 +167,17 @@
         if (buffer == null) {
             return null;
         }
+        final WindowState mainWindow = top.findMainWindow();
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
-                top.findMainWindow().mStableInsets, false /* reduced */, 1f /* scale */);
+                minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), false /* reduced */,
+                1f /* scale */);
+    }
+
+    private Rect minRect(Rect rect1, Rect rect2) {
+        return new Rect(Math.min(rect1.left, rect2.left),
+                Math.min(rect1.top, rect2.top),
+                Math.min(rect1.right, rect2.right),
+                Math.min(rect1.bottom, rect2.bottom));
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 04403e2..1591e48 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -16,20 +16,35 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.SurfaceControl.HIDDEN;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getColorViewLeftInset;
+import static com.android.internal.policy.DecorView.getColorViewTopInset;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.app.ActivityManager.TaskDescription;
-import android.graphics.Bitmap;
+import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -37,17 +52,22 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.view.IWindowSession;
 import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy.StartingSurface;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
 import com.android.internal.view.BaseIWindow;
 
 /**
@@ -57,19 +77,57 @@
  */
 class TaskSnapshotSurface implements StartingSurface {
 
+    private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
+
+    /**
+     * When creating the starting window, we use the exact same layout flags such that we end up
+     * with a window with the exact same dimensions etc. However, these flags are not used in layout
+     * and might cause other side effects so we exclude them.
+     */
+    private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+            | FLAG_NOT_TOUCHABLE
+            | FLAG_NOT_TOUCH_MODAL
+            | FLAG_ALT_FOCUSABLE_IM
+            | FLAG_NOT_FOCUSABLE
+            | FLAG_HARDWARE_ACCELERATED
+            | FLAG_IGNORE_CHEEK_PRESSES
+            | FLAG_LOCAL_FOCUS_MODE
+            | FLAG_SLIPPERY
+            | FLAG_WATCH_OUTSIDE_TOUCH
+            | FLAG_SPLIT_TOUCH
+            | FLAG_SCALED
+            | FLAG_SECURE;
+
     private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
     private static final int MSG_REPORT_DRAW = 0;
     private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
     private final Window mWindow;
     private final Surface mSurface;
+    private SurfaceControl mChildSurfaceControl;
     private final IWindowSession mSession;
     private final WindowManagerService mService;
+    private final Rect mTaskBounds;
+    private final Rect mStableInsets = new Rect();
+    private final Rect mContentInsets = new Rect();
+    private final Rect mFrame = new Rect();
+    private final TaskSnapshot mSnapshot;
+    private final CharSequence mTitle;
     private boolean mHasDrawn;
     private boolean mReportNextDraw;
-    private Paint mFillBackgroundPaint = new Paint();
+    private long mShownTime;
+    private final Handler mHandler;
+    private final boolean mSizeMismatch;
+    private final Paint mBackgroundPaint = new Paint();
+    private final Paint mStatusBarPaint = new Paint();
+    private final Paint mNavigationBarPaint = new Paint();
+    private final int mStatusBarColor;
+    private final int mNavigationBarColor;
+    private final int mSysUiVis;
+    private final int mWindowFlags;
+    private final int mWindowPrivateFlags;
 
     static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
-            GraphicBuffer snapshot) {
+            TaskSnapshot snapshot) {
 
         final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
         final Window window = new Window();
@@ -78,32 +136,51 @@
         final Surface surface = new Surface();
         final Rect tmpRect = new Rect();
         final Rect tmpFrame = new Rect();
+        final Rect taskBounds;
+        final Rect tmpContentInsets = new Rect();
+        final Rect tmpStableInsets = new Rect();
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
-        int fillBackgroundColor = Color.WHITE;
+        int backgroundColor = WHITE;
+        int statusBarColor = 0;
+        int navigationBarColor = 0;
+        final int sysUiVis;
+        final int windowFlags;
+        final int windowPrivateFlags;
         synchronized (service.mWindowMap) {
+            final WindowState mainWindow = token.findMainWindow();
+            if (mainWindow == null) {
+                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
+                        + token);
+                return null;
+            }
+            sysUiVis = mainWindow.getSystemUiVisibility();
+            windowFlags = mainWindow.getAttrs().flags;
+            windowPrivateFlags = mainWindow.getAttrs().privateFlags;
+
             layoutParams.type = TYPE_APPLICATION_STARTING;
-            layoutParams.format = snapshot.getFormat();
-            layoutParams.flags = FLAG_LAYOUT_INSET_DECOR
-                    | FLAG_LAYOUT_IN_SCREEN
+            layoutParams.format = snapshot.getSnapshot().getFormat();
+            layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
                     | FLAG_NOT_FOCUSABLE
-                    | FLAG_NOT_TOUCHABLE
-                    | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+                    | FLAG_NOT_TOUCHABLE;
             layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
             layoutParams.token = token.token;
             layoutParams.width = LayoutParams.MATCH_PARENT;
             layoutParams.height = LayoutParams.MATCH_PARENT;
-
-            // TODO: Inherit behavior whether to draw behind status bar/nav bar.
-            layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            layoutParams.systemUiVisibility = sysUiVis;
             final Task task = token.getTask();
             if (task != null) {
-                layoutParams.setTitle(String.format(TITLE_FORMAT,task.mTaskId));
+                layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
 
                 final TaskDescription taskDescription = task.getTaskDescription();
                 if (taskDescription != null) {
-                    fillBackgroundColor = taskDescription.getBackgroundColor();
+                    backgroundColor = taskDescription.getBackgroundColor();
+                    statusBarColor = taskDescription.getStatusBarColor();
+                    navigationBarColor = taskDescription.getNavigationBarColor();
                 }
+                taskBounds = new Rect();
+                task.getBounds(taskBounds);
+            } else {
+                taskBounds = null;
             }
         }
         try {
@@ -118,31 +195,57 @@
             // Local call.
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
-                surface, fillBackgroundColor);
+                surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
+                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds);
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
-                    tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration,
-                    surface);
+                    tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
+                    tmpMergedConfiguration, surface);
         } catch (RemoteException e) {
             // Local call.
         }
-        snapshotSurface.drawSnapshot(snapshot);
+        snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
+        snapshotSurface.drawSnapshot();
         return snapshotSurface;
     }
 
     @VisibleForTesting
     TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
-            int fillBackgroundColor) {
+            TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
+            int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
+            Rect taskBounds) {
         mService = service;
+        mHandler = new Handler(mService.mH.getLooper());
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = window;
         mSurface = surface;
-        mFillBackgroundPaint.setColor(fillBackgroundColor);
+        mSnapshot = snapshot;
+        mTitle = title;
+        mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+        mTaskBounds = taskBounds;
+        mSysUiVis = sysUiVis;
+        mWindowFlags = windowFlags;
+        mWindowPrivateFlags = windowPrivateFlags;
+        mSizeMismatch = (mFrame.width() != snapshot.getSnapshot().getWidth()
+                || mFrame.height() != snapshot.getSnapshot().getHeight());
+        mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
+                service.mContext.getColor(R.color.system_bar_background_semi_transparent),
+                statusBarColor);
+        mNavigationBarColor = navigationBarColor;
+        mStatusBarPaint.setColor(mStatusBarColor);
+        mNavigationBarPaint.setColor(navigationBarColor);
     }
 
     @Override
     public void remove() {
+        synchronized (mService.mWindowMap) {
+            final long now = SystemClock.uptimeMillis();
+            if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
+                mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
+                return;
+            }
+        }
         try {
             mSession.remove(mWindow);
         } catch (RemoteException e) {
@@ -150,31 +253,149 @@
         }
     }
 
-    private void drawSnapshot(GraphicBuffer snapshot) {
-        mSurface.attachAndQueueBuffer(snapshot);
+    @VisibleForTesting
+    void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
+        mFrame.set(frame);
+        mContentInsets.set(contentInsets);
+        mStableInsets.set(stableInsets);
+    }
+
+    private void drawSnapshot() {
+        final GraphicBuffer buffer = mSnapshot.getSnapshot();
+        if (mSizeMismatch) {
+            // The dimensions of the buffer and the window don't match, so attaching the buffer
+            // will fail. Better create a child window with the exact dimensions and fill the parent
+            // window with the background color!
+            drawSizeMismatchSnapshot(buffer);
+        } else {
+            drawSizeMatchSnapshot(buffer);
+        }
         final boolean reportNextDraw;
         synchronized (mService.mWindowMap) {
+            mShownTime = SystemClock.uptimeMillis();
             mHasDrawn = true;
             reportNextDraw = mReportNextDraw;
         }
         if (reportNextDraw) {
             reportDrawn();
         }
+    }
+
+    private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
+        mSurface.attachAndQueueBuffer(buffer);
+        mSurface.release();
+    }
+
+    private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
+        final SurfaceSession session = new SurfaceSession(mSurface);
+
+        // Keep a reference to it such that it doesn't get destroyed when finalized.
+        mChildSurfaceControl = new SurfaceControl(session,
+                mTitle + " - task-snapshot-surface",
+                buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN);
+        Surface surface = new Surface();
+        surface.copyFrom(mChildSurfaceControl);
+
+        // Clip off ugly navigation bar.
+        final Rect crop = calculateSnapshotCrop();
+        final Rect frame = calculateSnapshotFrame(crop);
+        SurfaceControl.openTransaction();
+        try {
+            // We can just show the surface here as it will still be hidden as the parent is
+            // still hidden.
+            mChildSurfaceControl.show();
+            mChildSurfaceControl.setWindowCrop(crop);
+            mChildSurfaceControl.setPosition(frame.left, frame.top);
+        } finally {
+            SurfaceControl.closeTransaction();
+        }
+        surface.attachAndQueueBuffer(buffer);
+        surface.release();
+
+        final Canvas c = mSurface.lockCanvas(null);
+        drawBackgroundAndBars(c, frame);
+        mSurface.unlockCanvasAndPost(c);
         mSurface.release();
     }
 
     @VisibleForTesting
-    void fillEmptyBackground(Canvas c, Bitmap b) {
-        final boolean fillHorizontally = c.getWidth() > b.getWidth();
-        final boolean fillVertically = c.getHeight() > b.getHeight();
+    Rect calculateSnapshotCrop() {
+        final Rect rect = new Rect();
+        rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
+        final Rect insets = mSnapshot.getContentInsets();
+
+        // Let's remove all system decorations except the status bar, but only if the task is at the
+        // very top of the screen.
+        rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom);
+        return rect;
+    }
+
+    @VisibleForTesting
+    Rect calculateSnapshotFrame(Rect crop) {
+        final Rect frame = new Rect(crop);
+
+        // By default, offset it to to top/left corner
+        frame.offsetTo(-crop.left, -crop.top);
+
+        // However, we also need to make space for the navigation bar on the left side.
+        final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
+                mContentInsets.left);
+        frame.offset(colorViewLeftInset, 0);
+        return frame;
+    }
+
+    @VisibleForTesting
+    void drawBackgroundAndBars(Canvas c, Rect frame) {
+        final int statusBarHeight = getStatusBarColorViewHeight();
+        final boolean fillHorizontally = c.getWidth() > frame.right;
+        final boolean fillVertically = c.getHeight() > frame.bottom;
         if (fillHorizontally) {
-            c.drawRect(b.getWidth(), 0, c.getWidth(), fillVertically
-                        ? b.getHeight()
-                        : c.getHeight(),
-                    mFillBackgroundPaint);
+            c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
+                    c.getWidth(), fillVertically
+                            ? frame.bottom
+                            : c.getHeight(),
+                    mBackgroundPaint);
         }
         if (fillVertically) {
-            c.drawRect(0, b.getHeight(), c.getWidth(), c.getHeight(), mFillBackgroundPaint);
+            c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
+        }
+        drawStatusBarBackground(c, frame, statusBarHeight);
+        drawNavigationBarBackground(c);
+    }
+
+    private int getStatusBarColorViewHeight() {
+        final boolean forceStatusBarBackground =
+                (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+        if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
+            return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
+        } else {
+            return 0;
+        }
+    }
+
+    private boolean isNavigationBarColorViewVisible() {
+        return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
+    }
+
+    @VisibleForTesting
+    void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) {
+        if (statusBarHeight > 0 && c.getWidth() > frame.right) {
+            final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
+                    mContentInsets.right);
+            c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+        }
+    }
+
+    @VisibleForTesting
+    void drawNavigationBarBackground(Canvas c) {
+        final Rect navigationBarRect = new Rect();
+        getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
+                navigationBarRect);
+        final boolean visible = isNavigationBarColorViewVisible();
+        if (visible && !navigationBarRect.isEmpty()) {
+            c.drawRect(navigationBarRect, mNavigationBarPaint);
         }
     }
 
@@ -211,10 +432,10 @@
         }
     };
 
-    private static class Window extends BaseIWindow {
+    @VisibleForTesting
+    static class Window extends BaseIWindow {
 
         private TaskSnapshotSurface mOuter;
-
         public void setOuter(TaskSnapshotSurface outer) {
             mOuter = outer;
         }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 57fb81c..57eaa2b 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -17,17 +17,15 @@
 package com.android.server.wm;
 
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
 
 import android.content.Context;
+import android.os.Handler;
 import android.os.Trace;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -36,6 +34,9 @@
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
 
+import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
+import com.android.server.DisplayThread;
+
 import java.io.PrintWriter;
 
 /**
@@ -82,20 +83,31 @@
     // check if some got replaced and can be removed.
     private boolean mRemoveReplacedWindows = false;
 
+    private long mCurrentFrameTime;
+    private final Runnable mAnimationTick;
+    private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
+
     WindowAnimator(final WindowManagerService service) {
         mService = service;
         mContext = service.mContext;
         mPolicy = service.mPolicy;
         mWindowPlacerLocked = service.mWindowPlacerLocked;
+        final Handler handler = DisplayThread.getHandler();
 
-        mAnimationFrameCallback = new Choreographer.FrameCallback() {
-            public void doFrame(long frameTimeNs) {
-                synchronized (mService.mWindowMap) {
-                    mService.mAnimationScheduled = false;
-                    animateLocked(frameTimeNs);
-                }
+        // TODO: Multi-display: If displays have different vsync tick, have a separate tick per
+        // display.
+        mSfChoreographer = new SurfaceFlingerVsyncChoreographer(handler,
+                mService.getDefaultDisplayContentLocked().getDisplay());
+        mAnimationTick = () -> {
+            synchronized (mService.mWindowMap) {
+                mService.mAnimationScheduled = false;
+                animateLocked(mCurrentFrameTime);
             }
         };
+        mAnimationFrameCallback = frameTimeNs -> {
+            mCurrentFrameTime = frameTimeNs;
+            mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
+        };
     }
 
     void addDisplayLocked(final int displayId) {
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
index 84ffc35..c4a6837 100644
--- a/services/core/java/com/android/server/wm/WindowContainerController.java
+++ b/services/core/java/com/android/server/wm/WindowContainerController.java
@@ -33,7 +33,7 @@
 
     final WindowManagerService mService;
     final RootWindowContainer mRoot;
-    final HashMap<IBinder, WindowState> mWindowMap;
+    final WindowHashMap mWindowMap;
 
     // The window container this controller owns.
     E mContainer;
diff --git a/services/core/java/com/android/server/wm/WindowHashMap.java b/services/core/java/com/android/server/wm/WindowHashMap.java
new file mode 100644
index 0000000..49bba41
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowHashMap.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+
+/**
+ * Subclass of HashMap such that we can instruct the compiler to boost our thread priority when
+ * locking this class. See makefile.
+ */
+class WindowHashMap extends HashMap<IBinder, WindowState> {
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 95fbbb8..1be0512 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -25,6 +26,11 @@
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_USER_HANDLE;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.myPid;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
@@ -60,6 +66,8 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.LockGuard.INDEX_WINDOW;
+import static com.android.server.LockGuard.installLock;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
@@ -102,6 +110,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
@@ -124,7 +133,6 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
 import android.net.Uri;
-import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -138,7 +146,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
-import android.os.Process;
+import android.os.PowerSaveState;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -150,10 +158,10 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.ArraySet;
-import android.util.MergedConfiguration;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -214,7 +222,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.LockGuard;
+import com.android.server.ThreadPriorityBooster;
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
@@ -238,10 +246,7 @@
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
-
-import static android.Manifest.permission.READ_FRAME_BUFFER;
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -407,7 +412,7 @@
      * This is also used as the lock for all of our state.
      * NOTE: Never call into methods that lock ActivityManagerService while holding this object.
      */
-    final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
+    final WindowHashMap mWindowMap = new WindowHashMap();
 
     /**
      * List of window tokens that have finished starting their application,
@@ -847,6 +852,16 @@
     // since they won't be notified through the app window animator.
     final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
+    private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster(
+            THREAD_PRIORITY_DISPLAY, INDEX_WINDOW);
+
+    static void boostPriorityForLockedSection() {
+        sThreadPriorityBooster.boost();
+    }
+
+    static void resetPriorityAfterLockedSection() {
+        sThreadPriorityBooster.reset();
+    }
 
     void openSurfaceTransaction() {
         synchronized (mWindowMap) {
@@ -935,7 +950,7 @@
     private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
             WindowManagerPolicy policy) {
-        LockGuard.installLock(this, LockGuard.INDEX_WINDOW);
+        installLock(this, INDEX_WINDOW);
         mRoot = new RootWindowContainer(this);
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -1580,7 +1595,7 @@
     @Override
     public void enableSurfaceTrace(ParcelFileDescriptor pfd) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
+        if (callingUid != SHELL_UID && callingUid != ROOT_UID) {
             throw new SecurityException("Only shell can call enableSurfaceTrace");
         }
 
@@ -1592,8 +1607,8 @@
     @Override
     public void disableSurfaceTrace() {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID &&
-            callingUid != Process.SYSTEM_UID) {
+        if (callingUid != SHELL_UID && callingUid != ROOT_UID &&
+            callingUid != SYSTEM_UID) {
             throw new SecurityException("Only shell can call disableSurfaceTrace");
         }
         synchronized (mWindowMap) {
@@ -1607,7 +1622,7 @@
     @Override
     public void setScreenCaptureDisabled(int userId, boolean disabled) {
         int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SYSTEM_UID) {
+        if (callingUid != SYSTEM_UID) {
             throw new SecurityException("Only system can call setScreenCaptureDisabled.");
         }
 
@@ -2263,7 +2278,7 @@
 
     boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
-        if (Binder.getCallingPid() == Process.myPid()) {
+        if (Binder.getCallingPid() == myPid()) {
             return true;
         }
 
@@ -2916,7 +2931,7 @@
         }
         // If this isn't coming from the system then don't allow disabling the lockscreen
         // to bypass security.
-        if (Binder.getCallingUid() != Process.SYSTEM_UID && isKeyguardSecure()) {
+        if (Binder.getCallingUid() != SYSTEM_UID && isKeyguardSecure()) {
             Log.d(TAG_WM, "current mode is SecurityMode, ignore disableKeyguard");
             return;
         }
@@ -3196,19 +3211,25 @@
     // Called by window manager policy.  Not exposed externally.
     @Override
     public void shutdown(boolean confirm) {
-        ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
+        // Pass in the UI context, since ShutdownThread requires it (to show UI).
+        ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),
+                PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
     }
 
     // Called by window manager policy.  Not exposed externally.
     @Override
     public void reboot(boolean confirm) {
-        ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
+        // Pass in the UI context, since ShutdownThread requires it (to show UI).
+        ShutdownThread.reboot(ActivityThread.currentActivityThread().getSystemUiContext(),
+                PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
     }
 
     // Called by window manager policy.  Not exposed externally.
     @Override
     public void rebootSafeMode(boolean confirm) {
-        ShutdownThread.rebootSafeMode(mContext, confirm);
+        // Pass in the UI context, since ShutdownThread requires it (to show UI).
+        ShutdownThread.rebootSafeMode(ActivityThread.currentActivityThread().getSystemUiContext(),
+                confirm);
     }
 
     public void setCurrentProfileIds(final int[] currentProfileIds) {
@@ -5312,8 +5333,8 @@
                     if (displayContent.mBaseDisplayWidth != width
                             || displayContent.mBaseDisplayHeight != height) {
                         Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
-                        displayContent.mBaseDisplayWidth = width;
-                        displayContent.mBaseDisplayHeight = height;
+                        displayContent.updateBaseDisplayMetrics(width, height,
+                                displayContent.mBaseDisplayDensity);
                     }
                 } catch (NumberFormatException ex) {
                 }
@@ -5338,8 +5359,7 @@
     // displayContent must not be null
     private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
         Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
-        displayContent.mBaseDisplayWidth = width;
-        displayContent.mBaseDisplayHeight = height;
+        displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity);
         reconfigureDisplayLocked(displayContent);
     }
 
@@ -7052,7 +7072,7 @@
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
             }
-            if (Binder.getCallingPid() != android.os.Process.myPid()) {
+            if (Binder.getCallingPid() != myPid()) {
                 spec.recycle();
             }
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
new file mode 100644
index 0000000..97fa9d5
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.IDeviceAdminService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.am.PersistentConnection;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Manages connections to persistent services in owner packages.
+ */
+public class DeviceAdminServiceController {
+    static final String TAG = DevicePolicyManagerService.LOG_TAG;
+
+    static final boolean DEBUG = false; // DO NOT MERGE WITH TRUE.
+
+    final Object mLock = new Object();
+    final Context mContext;
+
+    private final DevicePolicyManagerService mService;
+    private final DevicePolicyManagerService.Injector mInjector;
+
+    private final Handler mHandler; // needed?
+
+    static void debug(String format, Object... args) {
+        if (!DEBUG) {
+            return;
+        }
+        Slog.d(TAG, String.format(format, args));
+    }
+
+    private class DevicePolicyServiceConnection
+            extends PersistentConnection<IDeviceAdminService> {
+        public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) {
+            super(TAG, mContext, mHandler, userId, componentName);
+        }
+
+        @Override
+        protected IDeviceAdminService asInterface(IBinder binder) {
+            return IDeviceAdminService.Stub.asInterface(binder);
+        }
+    }
+
+    /**
+     * User-ID -> {@link PersistentConnection}.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<DevicePolicyServiceConnection> mConnections = new SparseArray<>();
+
+    public DeviceAdminServiceController(DevicePolicyManagerService service) {
+        mService = service;
+        mInjector = service.mInjector;
+        mContext = mInjector.mContext;
+        mHandler = new Handler(BackgroundThread.get().getLooper());
+    }
+
+    /**
+     * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE}
+     * in a given package.
+     */
+    @Nullable
+    private ServiceInfo findService(@NonNull String packageName, int userId) {
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE);
+        intent.setPackage(packageName);
+
+        try {
+            final ParceledListSlice<ResolveInfo> pls = mInjector.getIPackageManager()
+                    .queryIntentServices(intent, null, /* flags=*/ 0, userId);
+            if (pls == null) {
+                return null;
+            }
+            final List<ResolveInfo> list = pls.getList();
+            if (list.size() == 0) {
+                return null;
+            }
+            // Note if multiple services are found, that's an error, even if only one of them
+            // is exported.
+            if (list.size() > 1) {
+                Log.e(TAG, "More than one DeviceAdminService's found in package "
+                        + packageName
+                        + ".  They'll all be ignored.");
+                return null;
+            }
+            final ServiceInfo si = list.get(0).serviceInfo;
+            if (si.exported) {
+                Log.e(TAG, "DeviceAdminService must not be exported: '"
+                        + si.getComponentName().flattenToShortString()
+                        + "' will be ignored.");
+                return null;
+            }
+            return si;
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE}
+     * in an owner package and connect to it.
+     */
+    public void startServiceForOwner(@NonNull String packageName, int userId,
+            @NonNull String actionForLog) {
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                final ServiceInfo service = findService(packageName, userId);
+                if (service == null) {
+                    debug("Owner package %s on u%d has no service.",
+                            packageName, userId);
+                    disconnectServiceOnUserLocked(userId, actionForLog);
+                    return;
+                }
+                // See if it's already running.
+                final PersistentConnection<IDeviceAdminService> existing =
+                        mConnections.get(userId);
+                if (existing != null) {
+                    if (existing.getComponentName().equals(service.getComponentName())) {
+                        return;
+                    }
+                    disconnectServiceOnUserLocked(userId, actionForLog);
+                }
+
+                debug("Owner package %s on u%d has service %s for %s",
+                        packageName, userId,
+                        service.getComponentName().flattenToShortString(), actionForLog);
+
+                final DevicePolicyServiceConnection conn =
+                        new DevicePolicyServiceConnection(
+                                userId, service.getComponentName());
+                mConnections.put(userId, conn);
+                conn.connect();
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Stop an owner service on a given user.
+     */
+    public void stopServiceForOwner(int userId, @NonNull String actionForLog) {
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                disconnectServiceOnUserLocked(userId, actionForLog);
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) {
+        final DevicePolicyServiceConnection conn = mConnections.get(userId);
+        if (conn != null) {
+            debug("Stopping service for u%d if already running for %s.",
+                    userId, actionForLog);
+            conn.disconnect();
+            mConnections.remove(userId);
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        synchronized (mLock) {
+            if (mConnections.size() == 0) {
+                return;
+            }
+            pw.println();
+            pw.print(prefix); pw.println("Owner Services:");
+            for (int i = 0; i < mConnections.size(); i++) {
+                final int userId = mConnections.keyAt(i);
+                pw.print(prefix); pw.print("  "); pw.print("User: "); pw.println(userId);
+
+                final DevicePolicyServiceConnection con = mConnections.valueAt(i);
+                con.dump(prefix + "    ", pw);
+            }
+        }
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6f49324..bfa1b99 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -140,7 +140,6 @@
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsInternal;
 import android.provider.Settings;
-import android.security.Credentials;
 import android.security.IKeyChainAliasCallback;
 import android.security.IKeyChainService;
 import android.security.KeyChain;
@@ -194,7 +193,6 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.text.DateFormat;
-import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -365,6 +363,7 @@
     final UserManagerInternal mUserManagerInternal;
     final TelephonyManager mTelephonyManager;
     private final LockPatternUtils mLockPatternUtils;
+    private final DeviceAdminServiceController mDeviceAdminServiceController;
 
     /**
      * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
@@ -459,7 +458,17 @@
 
         @Override
         public void onStartUser(int userHandle) {
-            mService.onStartUser(userHandle);
+            mService.handleStartUser(userHandle);
+        }
+
+        @Override
+        public void onUnlockUser(int userHandle) {
+            mService.handleUnlockUser(userHandle);
+        }
+
+        @Override
+        public void onStopUser(int userHandle) {
+            mService.handleStopUser(userHandle);
         }
     }
 
@@ -1420,7 +1429,7 @@
         }
     }
 
-    private void handlePackagesChanged(String packageName, int userHandle) {
+    private void handlePackagesChanged(@Nullable String packageName, int userHandle) {
         boolean removedAdmin = false;
         if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
@@ -1434,9 +1443,9 @@
                     if (packageName == null || packageName.equals(adminPackage)) {
                         if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
                                 || mIPackageManager.getReceiverInfo(aa.info.getComponent(),
-                                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                                        userHandle) == null) {
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                userHandle) == null) {
                             removedAdmin = true;
                             policy.mAdminList.remove(i);
                             policy.mAdminMap.remove(aa.info.getComponent());
@@ -1461,6 +1470,13 @@
                 }
             }
 
+            // If it's an owner package, we may need to refresh the bound connection.
+            final ComponentName owner = getOwnerComponent(userHandle);
+            if ((packageName != null) && (owner != null)
+                    && (owner.getPackageName().equals(packageName))) {
+                startOwnerService(userHandle, "package-broadcast");
+            }
+
             // Persist updates if the removed package was an admin or delegate.
             if (removedAdmin || removedDelegate) {
                 saveSettingsLocked(policy.mUserHandle);
@@ -1791,6 +1807,8 @@
         // Needed when mHasFeature == false, because it controls the certificate warning text.
         mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
 
+        mDeviceAdminServiceController = new DeviceAdminServiceController(this);
+
         if (!mHasFeature) {
             // Skip the rest of the initialization
             return;
@@ -2943,7 +2961,7 @@
         loadOwners();
         cleanUpOldUsers();
         ensureUnknownSourcesRestrictionForProfileOwners();
-        onStartUser(UserHandle.USER_SYSTEM);
+        handleStartUser(UserHandle.USER_SYSTEM);
 
         // Register an observer for watching for user setup complete and settings changes.
         mSetupContentObserver.register();
@@ -2990,10 +3008,32 @@
         }
     }
 
-    private void onStartUser(int userId) {
+    void handleStartUser(int userId) {
         updateScreenCaptureDisabledInWindowManager(userId,
                 getScreenCaptureDisabled(null, userId));
         pushUserRestrictions(userId);
+
+        startOwnerService(userId, "start-user");
+    }
+
+    void handleUnlockUser(int userId) {
+        startOwnerService(userId, "unlock-user");
+    }
+
+    void handleStopUser(int userId) {
+        stopOwnerService(userId, "stop-user");
+    }
+
+    private void startOwnerService(int userId, String actionForLog) {
+        final ComponentName owner = getOwnerComponent(userId);
+        if (owner != null) {
+            mDeviceAdminServiceController.startServiceForOwner(
+                    owner.getPackageName(), userId, actionForLog);
+        }
+    }
+
+    private void stopOwnerService(int userId, String actionForLog) {
+        mDeviceAdminServiceController.stopServiceForOwner(userId, actionForLog);
     }
 
     private void cleanUpOldUsers() {
@@ -5078,7 +5118,7 @@
      * @param callerPackage the name of the calling package. Required if {@code who} is
      *            {@code null}.
      * @param reqPolicy the policy used in the API whose access permission is being checked.
-     * @param scoppe the delegation scope corresponding to the API being checked.
+     * @param scope the delegation scope corresponding to the API being checked.
      * @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy};
      *            or when {@code who} is {@code null} and {@code callerPackage} is not a delegate
      *            of {@code scope}.
@@ -6460,6 +6500,9 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
+            mDeviceAdminServiceController.startServiceForOwner(
+                    admin.getPackageName(), userId, "set-device-owner");
+
             Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
             return true;
         }
@@ -6615,6 +6658,8 @@
     }
 
     private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
+        mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-device-owner");
+
         if (admin != null) {
             admin.disableCamera = false;
             admin.userRestrictions = null;
@@ -6692,6 +6737,8 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
+            mDeviceAdminServiceController.startServiceForOwner(
+                    who.getPackageName(), userHandle, "set-profile-owner");
             return true;
         }
     }
@@ -6723,6 +6770,8 @@
     }
 
     public void clearProfileOwnerLocked(ActiveAdmin admin, int userId) {
+        mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-profile-owner");
+
         if (admin != null) {
             admin.disableCamera = false;
             admin.userRestrictions = null;
@@ -7275,6 +7324,7 @@
         synchronized (this) {
             pw.println("Current Device Policy Manager state:");
             mOwners.dump("  ", pw);
+            mDeviceAdminServiceController.dump("  ", pw);
             int userCount = mUserData.size();
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -9624,6 +9674,21 @@
         return null;
     }
 
+    /**
+     * Return device owner or profile owner set on a given user.
+     */
+    private @Nullable ComponentName getOwnerComponent(int userId) {
+        synchronized (this) {
+            if (mOwners.getDeviceOwnerUserId() == userId) {
+                return mOwners.getDeviceOwnerComponent();
+            }
+            if (mOwners.hasProfileOwner(userId)) {
+                return mOwners.getProfileOwnerComponent(userId);
+            }
+        }
+        return null;
+    }
+
     private int checkManagedUserProvisioningPreCondition(int callingUserId) {
         if (!hasFeatureManagedUsers()) {
             return CODE_MANAGED_USERS_NOT_SUPPORTED;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3f197b7..1312c8f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -475,6 +475,9 @@
         ActivityThread activityThread = ActivityThread.systemMain();
         mSystemContext = activityThread.getSystemContext();
         mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
+
+        final Context systemUiContext = activityThread.getSystemUiContext();
+        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
new file mode 100644
index 0000000..54ecab3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ActivityRecord} class.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.am.ActivityRecordTests
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityRecordTests extends ActivityTestsBase {
+    private final ComponentName testActivityComponent =
+            ComponentName.unflattenFromString("com.foo/.BarActivity");
+    @Test
+    public void testStackCleanupOnClearingTask() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+        final TaskRecord task = createTask(service, testActivityComponent, testStack);
+        final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+        record.setTask(null);
+        assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+    }
+
+    @Test
+    public void testStackCleanupOnActivityRemoval() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+        final TaskRecord task = createTask(service, testActivityComponent, testStack);
+        final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+        task.removeActivity(record);
+        assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+    }
+
+    @Test
+    public void testStackCleanupOnTaskRemoval() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+        final TaskRecord task = createTask(service, testActivityComponent, testStack);
+        final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+        testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING);
+        assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+    }
+
+    @Test
+    public void testNoCleanupMovingActivityInSameStack() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+        final TaskRecord oldTask = createTask(service, testActivityComponent, testStack);
+        final ActivityRecord record = createActivity(service, testActivityComponent, oldTask);
+        final TaskRecord newTask = createTask(service, testActivityComponent, testStack);
+
+        record.reparent(newTask, 0, null /*reason*/);
+        assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
new file mode 100644
index 0000000..c5cc2ff
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+import com.android.server.AttributeCache;
+import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.StackWindowController;
+
+import com.android.server.wm.WindowManagerService;
+import com.android.server.wm.WindowTestUtils;
+import org.junit.Before;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * A base class to handle common operations in activity related unit tests.
+ */
+public class ActivityTestsBase {
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private static boolean sLooperPrepared;
+    private Handler mHandler;
+
+    // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must
+    // be called at before any tests.
+    private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext);
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        if (!sLooperPrepared) {
+            sLooperPrepared = true;
+            Looper.prepare();
+        }
+    }
+
+    protected ActivityManagerService createActivityManagerService() {
+        return new TestActivityManagerService(mContext);
+    }
+
+    protected static TestActivityStack createActivityStack(ActivityManagerService service,
+            int stackId, int displayId, boolean onTop) {
+        if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
+            final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor)
+                    .createTestStack(stackId, onTop);
+            return stack;
+        }
+
+        return null;
+    }
+
+    protected static ActivityRecord createActivity(ActivityManagerService service,
+            ComponentName component, TaskRecord task) {
+        Intent intent = new Intent();
+        intent.setComponent(component);
+        final ActivityInfo aInfo = new ActivityInfo();
+        aInfo.applicationInfo = new ApplicationInfo();
+        aInfo.applicationInfo.packageName = component.getPackageName();
+        AttributeCache.init(service.mContext);
+        final ActivityRecord activity = new ActivityRecord(service, null /* caller */,
+                0 /* launchedFromPid */, 0, null, intent, null,
+                aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
+                0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
+                service.mStackSupervisor, null /* container */, null /* options */,
+                null /* sourceRecord */);
+        activity.mWindowContainerController = mock(AppWindowContainerController.class);
+
+        if (task != null) {
+            task.addActivityToTop(activity);
+        }
+
+        return activity;
+    }
+
+    protected static TaskRecord createTask(ActivityManagerService service,
+            ComponentName component, ActivityStack stack) {
+        final ActivityInfo aInfo = new ActivityInfo();
+        aInfo.applicationInfo = new ApplicationInfo();
+        aInfo.applicationInfo.packageName = component.getPackageName();
+
+        Intent intent = new Intent();
+        intent.setComponent(component);
+
+        final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
+                null /*_taskDescription*/, null /*thumbnailInfo*/);
+        stack.addTask(task, true, "creating test task");
+        task.setStack(stack);
+        task.createWindowContainer(true, true);
+
+        return task;
+    }
+
+    /**
+     * An {@link ActivityManagerService} subclass which provides a test
+     * {@link ActivityStackSupervisor}.
+     */
+    protected static class TestActivityManagerService extends ActivityManagerService {
+        public TestActivityManagerService(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected ActivityStackSupervisor createStackSupervisor() {
+            return new TestActivityStackSupervisor(this, new Handler().getLooper());
+        }
+    }
+
+    /**
+     * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
+     * setup not available in the test environment. Also specifies an injector for
+     */
+    protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
+        public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
+            super(service, looper);
+        }
+
+        // Invoked during {@link ActivityStack} creation.
+        @Override
+        void updateUIDsPresentOnDisplay() {
+        }
+
+        public TestActivityStack createTestStack(int stackId, boolean onTop) {
+            final ActivityDisplay display = new ActivityDisplay();
+            final TestActivityContainer container =
+                    new TestActivityContainer(stackId, display, onTop);
+            return container.getStack();
+        }
+
+        private class TestActivityContainer extends ActivityContainer {
+            private TestActivityStack mStack;
+            TestActivityContainer(int stackId, ActivityDisplay activityDisplay, boolean onTop) {
+                super(stackId, activityDisplay, onTop);
+            }
+
+            @Override
+            protected void createStack(int stackId, boolean onTop) {
+                mStack = new TestActivityStack(this, null /*recentTasks*/, onTop);
+            }
+
+            public TestActivityStack getStack() {
+                return mStack;
+            }
+        }
+    }
+
+    /**
+     * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a
+     * method is called. Note that its functionality depends on the implementations of the
+     * construction arguments.
+     */
+    protected static class TestActivityStack<T extends StackWindowController>
+            extends ActivityStack<T> {
+        private int mOnActivityRemovedFromStackCount = 0;
+        private T mContainerController;
+        TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
+                RecentTasks recentTasks, boolean onTop) {
+            super(activityContainer, recentTasks, onTop);
+        }
+
+        @Override
+        void onActivityRemovedFromStack(ActivityRecord r) {
+            mOnActivityRemovedFromStackCount++;
+            super.onActivityRemovedFromStack(r);
+        }
+
+        // Returns the number of times {@link #onActivityRemovedFromStack} has been called
+        public int onActivityRemovedFromStackInvocationCount() {
+            return mOnActivityRemovedFromStackCount;
+        }
+
+        @Override
+        protected T createStackWindowController(int displayId, boolean onTop,
+                Rect outBounds) {
+            mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+            return mContainerController;
+        }
+
+        @Override
+        T getWindowContainerController() {
+            return mContainerController;
+        }
+    }
+
+    protected static class ActivityStackBuilder {
+        private boolean mOnTop = true;
+        private int mStackId = 0;
+        private int mDisplayId = 1;
+
+        private final ActivityManagerService mService;
+
+        public ActivityStackBuilder(ActivityManagerService ams) {
+            mService = ams;
+        }
+
+        public ActivityStackBuilder setOnTop(boolean onTop) {
+            mOnTop = onTop;
+            return this;
+        }
+
+        public ActivityStackBuilder setStackId(int id) {
+            mStackId = id;
+            return this;
+        }
+
+        public ActivityStackBuilder setDisplayId(int id) {
+            mDisplayId = id;
+            return this;
+        }
+
+        public TestActivityStack build() {
+            return createActivityStack(mService, mStackId, mDisplayId, mOnTop);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index d0d23f8..d281e5a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1275,7 +1275,7 @@
         try {
             final ByteArrayOutputStream out = new ByteArrayOutputStream();
             final PrintWriter pw = new PrintWriter(out);
-            mService.dump(/* fd */ null, pw, args);
+            mService.dumpNoCheck(/* fd */ null, pw, args);
             pw.close();
 
             return out.toString();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index cd98654..9880caa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -2040,16 +2040,6 @@
         assertEquals(expected, dumpCheckin());
     }
 
-    public void testDumpsysNoPermission() {
-        assertExpectException(SecurityException.class, "android.permission.DUMP",
-                () -> mService.dump(null, new PrintWriter(new StringWriter()), null));
-
-        // System can call it without the permission.
-        runWithSystemUid(() -> {
-            mService.dump(null, new PrintWriter(new StringWriter()), null);
-        });
-    }
-
     /**
      * Make sure the legacy file format that only supported a single intent per shortcut
      * can still be read.
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 2ccaefc..25004de 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -44,7 +44,8 @@
 
     @Test
     public void testRemoveContainer() throws Exception {
-        final TestAppWindowContainerController controller = createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller =
+                createAppWindowController();
 
         // Assert token was added to display.
         assertNotNull(sDisplayContent.getWindowToken(controller.mToken.asBinder()));
@@ -61,7 +62,8 @@
 
     @Test
     public void testSetOrientation() throws Exception {
-        final TestAppWindowContainerController controller = createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller =
+                createAppWindowController();
 
         // Assert orientation is unspecified to start.
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
@@ -92,7 +94,8 @@
 
     @Test
     public void testCreateRemoveStartingWindow() throws Exception {
-        final TestAppWindowContainerController controller = createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller =
+                createAppWindowController();
         controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
         waitUntilHandlerIdle();
@@ -105,8 +108,10 @@
 
     @Test
     public void testTransferStartingWindow() throws Exception {
-        final TestAppWindowContainerController controller1 = createAppWindowController();
-        final TestAppWindowContainerController controller2 = createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller1 =
+                createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller2 =
+                createAppWindowController();
         controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
         waitUntilHandlerIdle();
@@ -120,8 +125,10 @@
 
     @Test
     public void testTransferStartingWindowWhileCreating() throws Exception {
-        final TestAppWindowContainerController controller1 = createAppWindowController();
-        final TestAppWindowContainerController controller2 = createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller1 =
+                createAppWindowController();
+        final WindowTestUtils.TestAppWindowContainerController controller2 =
+                createAppWindowController();
         sPolicy.setRunnableWhenAddingSplashScreen(() -> {
 
             // Surprise, ...! Transfer window in the middle of the creation flow.
@@ -140,16 +147,16 @@
     public void testReparent() throws Exception {
         final StackWindowController stackController =
             createStackControllerOnDisplay(sDisplayContent);
-        final TestTaskWindowContainerController taskController1 =
-                new TestTaskWindowContainerController(stackController);
-        final TestAppWindowContainerController appWindowController1 = createAppWindowController(
-                taskController1);
-        final TestTaskWindowContainerController taskController2 =
-                new TestTaskWindowContainerController(stackController);
-        final TestAppWindowContainerController appWindowController2 = createAppWindowController(
-                taskController2);
-        final TestTaskWindowContainerController taskController3 =
-                new TestTaskWindowContainerController(stackController);
+        final WindowTestUtils.TestTaskWindowContainerController taskController1 =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController);
+        final WindowTestUtils.TestAppWindowContainerController appWindowController1 =
+                createAppWindowController(taskController1);
+        final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController);
+        final WindowTestUtils.TestAppWindowContainerController appWindowController2 =
+                createAppWindowController(taskController2);
+        final WindowTestUtils.TestTaskWindowContainerController taskController3 =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController);
 
         try {
             appWindowController1.reparent(taskController1, 0);
@@ -169,16 +176,18 @@
         // Reparent the app window and ensure that it is moved
         appWindowController1.reparent(taskController2, 0);
         assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent());
-        assertEquals(0, ((TestAppWindowToken) appWindowController1.mContainer).positionInParent());
-        assertEquals(1, ((TestAppWindowToken) appWindowController2.mContainer).positionInParent());
+        assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer)
+                .positionInParent());
+        assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer)
+                .positionInParent());
     }
 
-    private TestAppWindowContainerController createAppWindowController() {
-        return createAppWindowController(new TestTaskWindowContainerController());
+    private WindowTestUtils.TestAppWindowContainerController createAppWindowController() {
+        return createAppWindowController(new WindowTestUtils.TestTaskWindowContainerController());
     }
 
-    private TestAppWindowContainerController createAppWindowController(
-            TestTaskWindowContainerController taskController) {
-        return new TestAppWindowContainerController(taskController);
+    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+            WindowTestUtils.TestTaskWindowContainerController taskController) {
+        return new WindowTestUtils.TestAppWindowContainerController(taskController);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 2003b91..7a7ca3f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -51,7 +51,8 @@
 
     @Test
     public void testAddWindow_Order() throws Exception {
-        final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final WindowTestUtils.TestAppWindowToken token =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
 
         assertEquals(0, token.getWindowsCount());
 
@@ -78,7 +79,8 @@
 
     @Test
     public void testFindMainWindow() throws Exception {
-        final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final WindowTestUtils.TestAppWindowToken token =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
 
         assertNull(token.findMainWindow());
 
@@ -102,12 +104,13 @@
         // Create an app window with token on a display.
         final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final TestAppWindowToken appWindowToken = new TestAppWindowToken(sDisplayContent);
+        final WindowTestUtils.TestAppWindowToken appWindowToken =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task.addChild(appWindowToken, 0);
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.setTitle("AppWindow");
-        final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
         appWindowToken.addWindow(appWindow);
 
         // Set initial orientation and update.
@@ -137,12 +140,13 @@
         final DisplayContent defaultDisplayContent = sWm.getDefaultDisplayContentLocked();
         final TaskStack stack = createTaskStackOnDisplay(defaultDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final TestAppWindowToken appWindowToken = new TestAppWindowToken(defaultDisplayContent);
+        final WindowTestUtils.TestAppWindowToken appWindowToken =
+                new WindowTestUtils.TestAppWindowToken(defaultDisplayContent);
         task.addChild(appWindowToken, 0);
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.setTitle("AppWindow");
-        final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
         appWindowToken.addWindow(appWindow);
 
         // Set initial orientation and update.
@@ -165,7 +169,8 @@
 
     @Test
     public void testGetOrientation() throws Exception {
-        final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final WindowTestUtils.TestAppWindowToken token =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         token.setFillsParent(false);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index e3ccd6e..d7d365e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -175,7 +175,7 @@
         assertEquals(dc, stack.getDisplayContent());
 
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final TestAppWindowToken token = new TestAppWindowToken(dc);
+        final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
         task.addChild(token, 0);
         assertEquals(dc, task.getDisplayContent());
         assertEquals(dc, token.getDisplayContent());
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
index b0eba0b..13098f6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -16,12 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-
 import android.graphics.Rect;
-import android.hardware.display.DisplayManagerGlobal;
-import android.view.Display;
-import android.view.DisplayInfo;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -48,8 +43,8 @@
     public void testRemoveContainer() throws Exception {
         final StackWindowController stackController =
                 createStackControllerOnDisplay(sDisplayContent);
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stackController);
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController);
 
         final TaskStack stack = stackController.mContainer;
         final Task task = taskController.mContainer;
@@ -68,11 +63,11 @@
     public void testRemoveContainer_deferRemoval() throws Exception {
         final StackWindowController stackController =
                 createStackControllerOnDisplay(sDisplayContent);
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stackController);
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController);
 
         final TaskStack stack = stackController.mContainer;
-        final TestTask task = (TestTask) taskController.mContainer;
+        final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer;
         // Stack removal is deferred if one of its child is animating.
         task.setLocalIsAnimating(true);
 
@@ -96,9 +91,9 @@
         final StackWindowController stack1Controller =
                 createStackControllerOnDisplay(sDisplayContent);
         final TaskStack stack1 = stack1Controller.mContainer;
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stack1Controller);
-        final TestTask task1 = (TestTask) taskController.mContainer;
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(stack1Controller);
+        final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer;
         task1.mOnDisplayChangedCalled = false;
 
         // Create second display and put second stack on it.
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index aab75ee..717ddf2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
@@ -24,15 +27,19 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
+import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Surface;
 
-import org.junit.Before;
+import com.android.server.wm.TaskSnapshotSurface.Window;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -48,59 +55,174 @@
 
     private TaskSnapshotSurface mSurface;
 
-    @Before
-    public void setUp() {
-        mSurface = new TaskSnapshotSurface(null, null, null, Color.WHITE);
+    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
+            int windowFlags, Rect taskBounds) {
+        final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
+                GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
+        final TaskSnapshot snapshot = new TaskSnapshot(buffer,
+                ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
+        mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
+                Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds);
+    }
+
+    private void setupSurface(int width, int height) {
+        setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, width, height));
     }
 
     @Test
     public void fillEmptyBackground_fillHorizontally() throws Exception {
+        setupSurface(200, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(100);
-        final Bitmap b = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
-        mSurface.fillEmptyBackground(mockCanvas, b);
+        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_fillVertically() throws Exception {
+        setupSurface(100, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(200);
-        final Bitmap b = Bitmap.createBitmap(200, 100, Config.ARGB_8888);
-        mSurface.fillEmptyBackground(mockCanvas, b);
+        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_fillBoth() throws Exception {
+        setupSurface(200, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(200);
-        final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
-        mSurface.fillEmptyBackground(mockCanvas, b);
+        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_dontFill_sameSize() throws Exception {
+        setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
-        mSurface.fillEmptyBackground(mockCanvas, b);
+        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
     @Test
     public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception {
+        setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        final Bitmap b = Bitmap.createBitmap(200, 200, Config.ARGB_8888);
-        mSurface.fillEmptyBackground(mockCanvas, b);
+        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
+
+    @Test
+    public void testCalculateSnapshotCrop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 100, 90), mSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_taskNotOnTop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100));
+        assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarLeft() {
+        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(10, 0, 100, 100), mSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarRight() {
+        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 90, 100), mSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 0, 10);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        assertEquals(new Rect(0, -10, 100, 70),
+                mSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame_navBarLeft() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(10, 10, 0, 0);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        assertEquals(new Rect(0, -10, 90, 80),
+                mSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+    }
+
+    @Test
+    public void testDrawStatusBarBackground() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10);
+        verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
+    public void testDrawStatusBarBackground_nope() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10);
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground() {
+        final Rect insets = new Rect(0, 10, 0, 10);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_left() {
+        final Rect insets = new Rect(10, 10, 0, 0);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_right() {
+        final Rect insets = new Rect(0, 10, 10, 0);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 462bd68..82ea2313 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -56,7 +56,7 @@
         // Stack should contain visible app window to be considered visible.
         final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
         assertFalse(mPinnedStack.isVisible());
-        final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent);
+        final WindowTestUtils.TestAppWindowToken pinnedApp = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         pinnedTask.addChild(pinnedApp, 0 /* addPos */);
         assertTrue(mPinnedStack.isVisible());
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 9dbd8a6..267e5f7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import android.content.pm.ActivityInfo;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -67,12 +64,14 @@
     public void testClosingAppDifferentStackOrientation() throws Exception {
         final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
-        TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+        WindowTestUtils.TestAppWindowToken appWindowToken1 =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task1.addChild(appWindowToken1, 0);
         appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         final Task task2 = createTaskInStack(stack, 1 /* userId */);
-        TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+        WindowTestUtils.TestAppWindowToken appWindowToken2 =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task2.addChild(appWindowToken2, 0);
         appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
 
@@ -85,12 +84,14 @@
     public void testMoveTaskToBackDifferentStackOrientation() throws Exception {
         final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
-        TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+        WindowTestUtils.TestAppWindowToken appWindowToken1 =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task1.addChild(appWindowToken1, 0);
         appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         final Task task2 = createTaskInStack(stack, 1 /* userId */);
-        TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+        WindowTestUtils.TestAppWindowToken appWindowToken2 =
+                new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task2.addChild(appWindowToken2, 0);
         appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index f79908e..1819c56 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -16,14 +16,9 @@
 
 package com.android.server.wm;
 
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-
-import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.Display;
-import android.view.DisplayInfo;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,10 +40,10 @@
 
     @Test
     public void testRemoveContainer() throws Exception {
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController();
-        final TestAppWindowContainerController appController =
-                new TestAppWindowContainerController(taskController);
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController();
+        final WindowTestUtils.TestAppWindowContainerController appController =
+                new WindowTestUtils.TestAppWindowContainerController(taskController);
 
         taskController.removeContainer();
         // Assert that the container was removed.
@@ -58,12 +53,12 @@
 
     @Test
     public void testRemoveContainer_deferRemoval() throws Exception {
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController();
-        final TestAppWindowContainerController appController =
-                new TestAppWindowContainerController(taskController);
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController();
+        final WindowTestUtils.TestAppWindowContainerController appController =
+                new WindowTestUtils.TestAppWindowContainerController(taskController);
 
-        final TestTask task = (TestTask) taskController.mContainer;
+        final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer;
         final AppWindowToken app = appController.mContainer;
         task.mShouldDeferRemoval = true;
 
@@ -85,12 +80,12 @@
     public void testReparent() throws Exception {
         final StackWindowController stackController1 =
                 createStackControllerOnDisplay(sDisplayContent);
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stackController1);
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController1);
         final StackWindowController stackController2 =
                 createStackControllerOnDisplay(sDisplayContent);
-        final TestTaskWindowContainerController taskController2 =
-                new TestTaskWindowContainerController(stackController2);
+        final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+                new WindowTestUtils.TestTaskWindowContainerController(stackController2);
 
         boolean gotException = false;
         try {
@@ -114,8 +109,8 @@
 
         taskController.reparent(stackController2, 0);
         assertEquals(stackController2.mContainer, taskController.mContainer.getParent());
-        assertEquals(0, ((TestTask) taskController.mContainer).positionInParent());
-        assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent());
+        assertEquals(0, ((WindowTestUtils.TestTask) taskController.mContainer).positionInParent());
+        assertEquals(1, ((WindowTestUtils.TestTask) taskController2.mContainer).positionInParent());
     }
 
     @Test
@@ -124,9 +119,9 @@
         final StackWindowController stack1Controller =
                 createStackControllerOnDisplay(sDisplayContent);
         final TaskStack stack1 = stack1Controller.mContainer;
-        final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stack1Controller);
-        final TestTask task1 = (TestTask) taskController.mContainer;
+        final WindowTestUtils.TestTaskWindowContainerController taskController =
+                new WindowTestUtils.TestTaskWindowContainerController(stack1Controller);
+        final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer;
         task1.mOnDisplayChangedCalled = false;
         assertEquals(sDisplayContent, stack1.getDisplayContent());
 
@@ -134,9 +129,10 @@
         final DisplayContent dc = createNewDisplay();
         final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
         final TaskStack stack2 = stack2Controller.mContainer;
-        final TestTaskWindowContainerController taskController2 =
-                new TestTaskWindowContainerController(stack2Controller);
-        final TestTask task2 = (TestTask) taskController2.mContainer;
+        final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+                new WindowTestUtils.TestTaskWindowContainerController(stack2Controller);
+        final WindowTestUtils.TestTask task2 =
+                (WindowTestUtils.TestTask) taskController2.mContainer;
 
         // Reparent and check state
         taskController.reparent(stack2Controller, 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index cf8af67..0eaf5bc 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -46,7 +46,7 @@
 
     @Test
     public void testFlow() throws Exception {
-        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         sWm.mUnknownAppVisibilityController.notifyLaunched(token);
         sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
         sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
@@ -58,8 +58,8 @@
 
     @Test
     public void testMultiple() throws Exception {
-        final AppWindowToken token1 = new TestAppWindowToken(sDisplayContent);
-        final AppWindowToken token2 = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token1 = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token2 = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
         sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
         sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
@@ -74,7 +74,7 @@
 
     @Test
     public void testClear() throws Exception {
-        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         sWm.mUnknownAppVisibilityController.notifyLaunched(token);
         sWm.mUnknownAppVisibilityController.clear();;
         assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
@@ -82,7 +82,7 @@
 
     @Test
     public void testAppRemoved() throws Exception {
-        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         sWm.mUnknownAppVisibilityController.notifyLaunched(token);
         sWm.mUnknownAppVisibilityController.appRemoved(token);
         assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 2e6eac0..a2aa058 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -102,7 +102,7 @@
         // Just any non zero value.
         sWm.mSystemDecorLayer = 10000;
 
-        mWindowToken = new TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
+        mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
         mStubStack = new TaskStack(sWm, 0);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
new file mode 100644
index 0000000..3a44357
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IBinder;
+import android.view.IApplicationToken;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.EMPTY;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static org.mockito.Mockito.mock;
+
+/**
+ * A collection of static functions that can be referenced by other test packages to provide access
+ * to WindowManager related test functionality.
+ */
+public class WindowTestUtils {
+    public static int sNextTaskId = 0;
+
+    /**
+     * Retrieves an instance of {@link WindowManagerService}, creating it if necessary.
+     */
+    public static WindowManagerService getWindowManagerService(Context context) {
+        return TestWindowManagerPolicy.getWindowManagerService(context);
+    }
+
+    /**
+     * Creates a mock instance of {@link StackWindowController}.
+     */
+    public static StackWindowController createMockStackWindowContainerController() {
+        StackWindowController controller = mock(StackWindowController.class);
+        controller.mContainer = mock(TestTaskStack.class);
+        return controller;
+    }
+
+    /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
+    public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
+            int userId) {
+        final Task newTask = new Task(WindowTestUtils.sNextTaskId++, stack, userId, service, null,
+                EMPTY, 0, false,
+                false, new ActivityManager.TaskDescription(), null);
+        stack.addTask(newTask, POSITION_TOP);
+        return newTask;
+    }
+
+    /**
+     * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not
+     * normally be mocked out.
+     */
+    public static class TestTaskStack extends TaskStack {
+        TestTaskStack(WindowManagerService service, int stackId) {
+            super(service, stackId);
+        }
+
+        @Override
+        void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
+            // Do nothing.
+        }
+    }
+
+    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
+    public static class TestAppWindowToken extends AppWindowToken {
+
+        TestAppWindowToken(DisplayContent dc) {
+            super(WindowTestsBase.sWm, null, false, dc, true /* fillsParent */,
+                    null /* overrideConfig */, null /* bounds */);
+        }
+
+        TestAppWindowToken(WindowManagerService service, IApplicationToken token,
+                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+                boolean alwaysFocusable, AppWindowContainerController controller,
+                Configuration overrideConfig, Rect bounds) {
+            super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
+                    showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
+                    launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+
+        WindowState getFirstChild() {
+            return mChildren.getFirst();
+        }
+
+        WindowState getLastChild() {
+            return mChildren.getLast();
+        }
+
+        int positionInParent() {
+            return getParent().mChildren.indexOf(this);
+        }
+    }
+
+    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
+    public static class TestWindowToken extends WindowToken {
+        int adj = 0;
+
+        TestWindowToken(int type, DisplayContent dc) {
+            this(type, dc, false /* persistOnEmpty */);
+        }
+
+        TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
+            super(WindowTestsBase.sWm, mock(IBinder.class), type, persistOnEmpty, dc,
+                    false /* ownerCanManageAppTokens */);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+
+        @Override
+        int getAnimLayerAdjustment() {
+            return adj;
+        }
+    }
+
+    /* Used so we can gain access to some protected members of the {@link Task} class */
+    public static class TestTask extends Task {
+        boolean mShouldDeferRemoval = false;
+        boolean mOnDisplayChangedCalled = false;
+        private boolean mUseLocalIsAnimating = false;
+        private boolean mIsAnimating = false;
+
+        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+                boolean homeTask, TaskWindowContainerController controller) {
+            super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
+                    supportsPictureInPicture, homeTask, new ActivityManager.TaskDescription(),
+                    controller);
+        }
+
+        boolean shouldDeferRemoval() {
+            return mShouldDeferRemoval;
+        }
+
+        int positionInParent() {
+            return getParent().mChildren.indexOf(this);
+        }
+
+        @Override
+        void onDisplayChanged(DisplayContent dc) {
+            super.onDisplayChanged(dc);
+            mOnDisplayChangedCalled = true;
+        }
+
+        @Override
+        boolean isAnimating() {
+            return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+        }
+
+        void setLocalIsAnimating(boolean isAnimating) {
+            mUseLocalIsAnimating = true;
+            mIsAnimating = isAnimating;
+        }
+    }
+
+    /**
+     * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
+     * class.
+     */
+    public static class TestTaskWindowContainerController extends TaskWindowContainerController {
+
+        TestTaskWindowContainerController() {
+            this(WindowTestsBase.createStackControllerOnDisplay(WindowTestsBase.sDisplayContent));
+        }
+
+        TestTaskWindowContainerController(StackWindowController stackController) {
+            super(sNextTaskId++, new TaskWindowContainerListener() {
+                        @Override
+                        public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
+
+                        }
+
+                        @Override
+                        public void requestResize(Rect bounds, int resizeMode) {
+
+                        }
+                    }, stackController, 0 /* userId */, null /* bounds */,
+                    EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
+                    false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
+                    true /* showForAllUsers */, new ActivityManager.TaskDescription(), WindowTestsBase.sWm);
+        }
+
+        @Override
+        TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
+                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+                boolean homeTask, ActivityManager.TaskDescription taskDescription) {
+            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+                    supportsPictureInPicture, homeTask, this);
+        }
+    }
+
+    public static class TestAppWindowContainerController extends AppWindowContainerController {
+
+        final IApplicationToken mToken;
+
+        TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
+            this(taskController, new TestIApplicationToken());
+        }
+
+        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
+                IApplicationToken token) {
+            super(taskController, token, null /* listener */, 0 /* index */,
+                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
+                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
+                    false /* launchTaskBehind */, false /* alwaysFocusable */,
+                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
+                    0 /* inputDispatchingTimeoutNanos */, WindowTestsBase.sWm, null /* overrideConfig */,
+                    null /* bounds */);
+            mToken = token;
+        }
+
+        @Override
+        AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
+                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+                boolean alwaysFocusable, AppWindowContainerController controller,
+                Configuration overrideConfig, Rect bounds) {
+            return new TestAppWindowToken(service, token, voiceInteraction, dc,
+                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
+                    orientation,
+                    rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+                    controller, overrideConfig, bounds);
+        }
+
+        AppWindowToken getAppWindowToken() {
+            return (AppWindowToken) WindowTestsBase.sDisplayContent.getWindowToken(mToken.asBinder());
+        }
+    }
+
+    public static class TestIApplicationToken implements IApplicationToken {
+
+        private final Binder mBinder = new Binder();
+        @Override
+        public IBinder asBinder() {
+            return mBinder;
+        }
+    }
+
+    /** Used to track resize reports. */
+    public static class TestWindowState extends WindowState {
+        boolean resizeReported;
+
+        TestWindowState(WindowManagerService service, Session session, IWindow window,
+                WindowManager.LayoutParams attrs, WindowToken token) {
+            super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0,
+                    false /* ownerCanAddInternalSystemWindow */);
+        }
+
+        @Override
+        void reportResized() {
+            super.reportResized();
+            resizeReported = true;
+        }
+
+        @Override
+        public boolean isGoneForLayoutLw() {
+            return false;
+        }
+
+        @Override
+        void updateResizingWindowIfNeeded() {
+            // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
+            // the system that it can actually update the window.
+            boolean hadSurface = mHasSurface;
+            mHasSurface = true;
+
+            super.updateResizingWindowIfNeeded();
+
+            mHasSurface = hadSurface;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index a9d930f..eaf4ac4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -19,21 +19,16 @@
 import static android.view.View.VISIBLE;
 
 import android.app.ActivityManager.TaskDescription;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
-import android.os.Binder;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.IApplicationToken;
 import org.junit.Assert;
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.MockitoAnnotations;
 
-import android.app.ActivityManager.TaskSnapshot;
 import android.content.Context;
-import android.os.IBinder;
 import android.support.test.InstrumentationRegistry;
 import android.view.IWindow;
 import android.view.WindowManager;
@@ -41,10 +36,6 @@
 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -58,7 +49,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static org.mockito.Mockito.mock;
 
 import com.android.server.AttributeCache;
@@ -78,8 +68,7 @@
     // make sure we don't collide with any existing display. If we run into no other display, the
     // added display should be treated as default. This cannot be the default display
     private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
-    static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
-    private static int sNextTaskId = 0;
+    private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
 
     private static boolean sOneTimeSetupDone = false;
     static DisplayContent sDisplayContent;
@@ -184,14 +173,14 @@
 
     private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
         if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
-            return new TestWindowToken(type, dc);
+            return new WindowTestUtils.TestWindowToken(type, dc);
         }
 
         final TaskStack stack = stackId == INVALID_STACK_ID
                 ? createTaskStackOnDisplay(dc)
                 : createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final TestAppWindowToken token = new TestAppWindowToken(dc);
+        final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
         task.addChild(token, 0);
         return token;
     }
@@ -209,7 +198,7 @@
     }
 
     WindowState createAppWindow(Task task, int type, String name) {
-        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
         task.addChild(token, 0);
         return createWindow(null, type, token, name);
     }
@@ -260,10 +249,7 @@
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     static Task createTaskInStack(TaskStack stack, int userId) {
-        final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false,
-                false, new TaskDescription(), null);
-        stack.addTask(newTask, POSITION_TOP);
-        return newTask;
+        return WindowTestUtils.createTaskInStack(sWm, stack, userId);
     }
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
@@ -274,227 +260,10 @@
         return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm));
     }
 
-    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
-    static class TestWindowToken extends WindowToken {
-        int adj = 0;
-
-        TestWindowToken(int type, DisplayContent dc) {
-            this(type, dc, false /* persistOnEmpty */);
-        }
-
-        TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
-            super(sWm, mock(IBinder.class), type, persistOnEmpty, dc,
-                    false /* ownerCanManageAppTokens */);
-        }
-
-        int getWindowsCount() {
-            return mChildren.size();
-        }
-
-        boolean hasWindow(WindowState w) {
-            return mChildren.contains(w);
-        }
-
-        @Override
-        int getAnimLayerAdjustment() {
-            return adj;
-        }
+    /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
+    WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
+            WindowToken token) {
+        return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
     }
 
-    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
-    static class TestAppWindowToken extends AppWindowToken {
-
-        TestAppWindowToken(DisplayContent dc) {
-            super(sWm, null, false, dc, true /* fillsParent */, null /* overrideConfig */,
-                    null /* bounds */);
-        }
-
-        TestAppWindowToken(WindowManagerService service, IApplicationToken token,
-                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
-                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
-                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-                boolean alwaysFocusable, AppWindowContainerController controller,
-                Configuration overrideConfig, Rect bounds) {
-            super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
-                    showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
-                    launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds);
-        }
-
-        int getWindowsCount() {
-            return mChildren.size();
-        }
-
-        boolean hasWindow(WindowState w) {
-            return mChildren.contains(w);
-        }
-
-        WindowState getFirstChild() {
-            return mChildren.getFirst();
-        }
-
-        WindowState getLastChild() {
-            return mChildren.getLast();
-        }
-
-        int positionInParent() {
-            return getParent().mChildren.indexOf(this);
-        }
-    }
-
-    /* Used so we can gain access to some protected members of the {@link Task} class */
-    class TestTask extends Task {
-
-        boolean mShouldDeferRemoval = false;
-        boolean mOnDisplayChangedCalled = false;
-        private boolean mUseLocalIsAnimating = false;
-        private boolean mIsAnimating = false;
-
-        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-                boolean homeTask, TaskWindowContainerController controller) {
-            super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
-                    supportsPictureInPicture, homeTask, new TaskDescription(), controller);
-        }
-
-        boolean shouldDeferRemoval() {
-            return mShouldDeferRemoval;
-        }
-
-        int positionInParent() {
-            return getParent().mChildren.indexOf(this);
-        }
-
-        @Override
-        void onDisplayChanged(DisplayContent dc) {
-            super.onDisplayChanged(dc);
-            mOnDisplayChangedCalled = true;
-        }
-
-        @Override
-        boolean isAnimating() {
-            return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
-        }
-
-        void setLocalIsAnimating(boolean isAnimating) {
-            mUseLocalIsAnimating = true;
-            mIsAnimating = isAnimating;
-        }
-    }
-
-    /**
-     * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
-     * class.
-     */
-    class TestTaskWindowContainerController extends TaskWindowContainerController {
-
-        TestTaskWindowContainerController() {
-            this(createStackControllerOnDisplay(sDisplayContent));
-        }
-
-        TestTaskWindowContainerController(StackWindowController stackController) {
-            super(sNextTaskId++, new TaskWindowContainerListener() {
-                        @Override
-                        public void onSnapshotChanged(TaskSnapshot snapshot) {
-
-                        }
-
-                        @Override
-                        public void requestResize(Rect bounds, int resizeMode) {
-
-                        }
-                    }, stackController, 0 /* userId */, null /* bounds */,
-                    EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
-                    false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
-                    true /* showForAllUsers */, new TaskDescription(), sWm);
-        }
-
-        @Override
-        TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
-                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-                boolean homeTask, TaskDescription taskDescription) {
-            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
-                    supportsPictureInPicture, homeTask, this);
-        }
-    }
-
-    class TestAppWindowContainerController extends AppWindowContainerController {
-
-        final IApplicationToken mToken;
-
-        TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
-            this(taskController, new TestIApplicationToken());
-        }
-
-        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
-                IApplicationToken token) {
-            super(taskController, token, null /* listener */, 0 /* index */,
-                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
-                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
-                    false /* launchTaskBehind */, false /* alwaysFocusable */,
-                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
-                    0 /* inputDispatchingTimeoutNanos */, sWm, null /* overrideConfig */,
-                    null /* bounds */);
-            mToken = token;
-        }
-
-        @Override
-        AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
-                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
-                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
-                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-                boolean alwaysFocusable, AppWindowContainerController controller,
-                Configuration overrideConfig, Rect bounds) {
-            return new TestAppWindowToken(service, token, voiceInteraction, dc,
-                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
-                    orientation,
-                    rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
-                    controller, overrideConfig, bounds);
-        }
-
-        AppWindowToken getAppWindowToken() {
-            return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder());
-        }
-    }
-
-    class TestIApplicationToken implements IApplicationToken {
-
-        private final Binder mBinder = new Binder();
-        @Override
-        public IBinder asBinder() {
-            return mBinder;
-        }
-    }
-
-    /** Used to track resize reports. */
-    class TestWindowState extends WindowState {
-        boolean resizeReported;
-
-        TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
-            super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
-                    false /* ownerCanAddInternalSystemWindow */);
-        }
-
-        @Override
-        void reportResized() {
-            super.reportResized();
-            resizeReported = true;
-        }
-
-        @Override
-        public boolean isGoneForLayoutLw() {
-            return false;
-        }
-
-        @Override
-        void updateResizingWindowIfNeeded() {
-            // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
-            // the system that it can actually update the window.
-            boolean hadSurface = mHasSurface;
-            mHasSurface = true;
-
-            super.updateResizingWindowIfNeeded();
-
-            mHasSurface = hadSurface;
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index babb6d9..4f7ad41 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -46,7 +46,8 @@
 
     @Test
     public void testAddWindow() throws Exception {
-        final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
+        final WindowTestUtils.TestWindowToken token =
+                new WindowTestUtils.TestWindowToken(0, sDisplayContent);
 
         assertEquals(0, token.getWindowsCount());
 
@@ -76,7 +77,7 @@
     @Test
     public void testChildRemoval() throws Exception {
         final DisplayContent dc = sDisplayContent;
-        final TestWindowToken token = new TestWindowToken(0, dc);
+        final WindowTestUtils.TestWindowToken token = new WindowTestUtils.TestWindowToken(0, dc);
 
         assertEquals(token, dc.getWindowToken(token.token));
 
@@ -95,7 +96,8 @@
 
     @Test
     public void testAdjustAnimLayer() throws Exception {
-        final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
+        final WindowTestUtils.TestWindowToken token =
+                new WindowTestUtils.TestWindowToken(0, sDisplayContent);
         final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
         final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
         final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
@@ -135,8 +137,9 @@
      */
     @Test
     public void testTokenRemovalProcess() throws Exception {
-        final TestWindowToken token =
-                new TestWindowToken(TYPE_TOAST, sDisplayContent, true /* persistOnEmpty */);
+        final WindowTestUtils.TestWindowToken token =
+                new WindowTestUtils.TestWindowToken(TYPE_TOAST, sDisplayContent,
+                        true /* persistOnEmpty */);
 
         // Verify that the token is on the display
         assertNotNull(sDisplayContent.getWindowToken(token.token));
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index 7b8ebd4..01e36f5 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -1039,18 +1039,34 @@
      * Start the appropriate package when an device/accessory got attached.
      *
      * @param intent The intent to start the package
-     * @param matches The available resolutions of the intent
+     * @param rawMatches The available resolutions of the intent
      * @param defaultActivity The default activity for the device (if set)
      * @param device The device if a device was attached
      * @param accessory The accessory if a device was attached
      */
-    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
+    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> rawMatches,
             @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device,
             @Nullable UsbAccessory accessory) {
-        int count = matches.size();
+        final int numRawMatches = rawMatches.size();
+
+        // The raw matches contain the activities that can be started but also the intents to switch
+        // between the profiles
+        int numParentActivityMatches = 0;
+        int numNonParentActivityMatches = 0;
+        for (int i = 0; i < numRawMatches; i++) {
+            final ResolveInfo rawMatch = rawMatches.get(i);
+            if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+                if (UserHandle.getUserHandleForUid(
+                        rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) {
+                    numParentActivityMatches++;
+                } else {
+                    numNonParentActivityMatches++;
+                }
+            }
+        }
 
         // don't show the resolver activity if there are no choices available
-        if (count == 0) {
+        if (numParentActivityMatches + numNonParentActivityMatches == 0) {
             if (accessory != null) {
                 String uri = accessory.getUri();
                 if (uri != null && uri.length() > 0) {
@@ -1073,6 +1089,21 @@
             return;
         }
 
+        // If only one profile has activity matches, we need to remove all switch intents
+        ArrayList<ResolveInfo> matches;
+        if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) {
+            matches = new ArrayList<>(numParentActivityMatches + numNonParentActivityMatches);
+
+            for (int i = 0; i < numRawMatches; i++) {
+                ResolveInfo rawMatch = rawMatches.get(i);
+                if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+                    matches.add(rawMatch);
+                }
+            }
+        } else {
+            matches = rawMatches;
+        }
+
         if (defaultActivity != null) {
             UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser(
                     UserHandle.getUserId(defaultActivity.applicationInfo.uid));
@@ -1101,7 +1132,7 @@
             resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             UserHandle user;
 
-            if (count == 1) {
+            if (matches.size() == 1) {
                 ResolveInfo rInfo = matches.get(0);
 
                 // start UsbConfirmActivity if there is only one choice
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 201f3ad..81f6600 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1178,6 +1178,7 @@
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+        intent.putExtra(Intent.EXTRA_SUBSCRIPTION_INDEX, subId);
         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
         //FIXME this is using phoneId and slotIndex interchangeably
         //Eventually, this should be removed as it is not the slot id
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 73ee25a..b4c531e 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -334,9 +334,11 @@
      * <ul>
      *   <li><em>subscription</em> - A int, the current default subscription.</li>
      * </ul>
+     * @deprecated Use {@link Intent#ACTION_DEFAULT_SUBSCRIPTION_CHANGED}
      */
+    @Deprecated
     public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
-            = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+            = Intent.ACTION_DEFAULT_SUBSCRIPTION_CHANGED;
 
     /**
      * Broadcast Action: The default data subscription has changed.  This has the following
@@ -364,9 +366,11 @@
      * <ul>
      *   <li><em>subscription</em> - A int, the current sms default subscription.</li>
      * </ul>
+     * @deprecated Use {@link Intent#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED}
      */
+    @Deprecated
     public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED
-            = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+            = Intent.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED;
 
     /*
      * Broadcast Action: An attempt to set phone radio type and access technology has changed.
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java
index 1cb394e..42f7955 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java
@@ -89,7 +89,10 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mCloseGuard.warnIfOpen();
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
             release();
         } finally {
             super.finalize();
diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk
new file mode 100644
index 0000000..e4cbe93
--- /dev/null
+++ b/tests/WindowManagerStressTest/Android.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := WindowManagerStressTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/WindowManagerStressTest/AndroidManifest.xml b/tests/WindowManagerStressTest/AndroidManifest.xml
new file mode 100644
index 0000000..17e0f15
--- /dev/null
+++ b/tests/WindowManagerStressTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="test.windowmanagerstresstest">
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/WindowManagerStressTest/res/layout/activity_main.xml b/tests/WindowManagerStressTest/res/layout/activity_main.xml
new file mode 100644
index 0000000..6cf8269
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="test.amslam.MainActivity">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/run"
+        android:text="@string/run" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/output" />
+
+</LinearLayout>
diff --git a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/values/colors.xml b/tests/WindowManagerStressTest/res/values/colors.xml
new file mode 100644
index 0000000..4270ca6
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/dimens.xml b/tests/WindowManagerStressTest/res/values/dimens.xml
new file mode 100644
index 0000000..ed4ccbc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!-- 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.
+-->
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/strings.xml b/tests/WindowManagerStressTest/res/values/strings.xml
new file mode 100644
index 0000000..cef05dc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="app_name">WmSlam</string>
+    <string name="run">Run</string>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/styles.xml b/tests/WindowManagerStressTest/res/values/styles.xml
new file mode 100644
index 0000000..0983b25
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!-- 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.
+-->
+<resources>
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="android:colorPrimary">@color/colorPrimary</item>
+        <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="android:colorAccent">@color/colorAccent</item>
+    </style>
+</resources>
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
new file mode 100644
index 0000000..6b9bb31
--- /dev/null
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package test.windowmanagerstresstest;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.MergedConfiguration;
+import android.view.Display;
+import android.view.IWindowSession;
+import android.view.Surface;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
+import android.widget.TextView;
+
+import com.android.internal.view.BaseIWindow;
+
+import java.util.ArrayList;
+
+public class MainActivity extends Activity {
+
+    private static final String TAG = "WmSlam";
+
+    private TextView mOutput;
+    private volatile boolean finished;
+    private final ArrayList<BaseIWindow> mWindows = new ArrayList<>();
+    private final LayoutParams mLayoutParams = new LayoutParams();
+    private final Rect mTmpRect = new Rect();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        mOutput = (TextView) findViewById(R.id.output);
+
+        findViewById(R.id.run).setOnClickListener(view -> {
+            view.setEnabled(false);
+            mOutput.setText("");
+            startBatch();
+        });
+        mLayoutParams.token = getActivityToken();
+    }
+
+    void startBatch() {
+        new Thread(() -> {
+            finished = false;
+            addWindows();
+            startCpuRunnables();
+            for (int i = 0; i < 5; i++) {
+                final long time = SystemClock.uptimeMillis();
+                slamWm();
+                log("Total: " + (SystemClock.uptimeMillis() - time) + " ms");
+            }
+            removeWindows();
+            finished = true;
+        }).start();
+    }
+
+    void startCpuRunnables() {
+        for (int i = 0; i < 10; i++) {
+            new Thread(mUseCpuRunnable).start();
+        }
+    }
+
+    private final Runnable mUseCpuRunnable = new Runnable() {
+        @Override
+        public void run() {
+            while (!finished) {
+            }
+        }
+    };
+
+    private void log(String text) {
+        mOutput.post(() -> mOutput.append(text + "\n"));
+        Log.d(TAG, text);
+    }
+
+    private void slamWm() {
+        ArrayList<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < 20; i++) {
+            for (BaseIWindow window : mWindows) {
+                Thread t = new Thread(() -> {
+                    try {
+                        WindowManagerGlobal.getWindowSession().relayout(window,
+                                window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, mTmpRect,
+                                mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
+                                new MergedConfiguration(), new Surface());
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                });
+                threads.add(t);
+                t.start();
+            }
+        }
+        for (Thread t : threads) {
+            try {
+                t.join();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    void addWindows() {
+        for (int i = 0; i < 50; i++) {
+            final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+            layoutParams.token = getActivityToken();
+            final BaseIWindow window = new BaseIWindow();
+            final IWindowSession session = WindowManagerGlobal.getWindowSession();
+            final Rect tmpRect = new Rect();
+            try {
+                final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq, layoutParams,
+                        View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+            mWindows.add(window);
+        }
+    }
+
+    void removeWindows() {
+        for (BaseIWindow window : mWindows) {
+            try {
+                WindowManagerGlobal.getWindowSession().remove(window);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2f5c97d..f449be7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -87,6 +87,7 @@
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
 import com.android.server.net.NetworkPinner;
+import com.android.server.net.NetworkPolicyManagerInternal;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -750,6 +751,9 @@
         }
 
         mServiceContext = new MockContext(getContext());
+        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
+        LocalServices.addService(
+                NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
         mService = new WrappedConnectivityService(mServiceContext,
                 mock(INetworkManagementService.class),
                 mock(INetworkStatsService.class),
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index cda8e6a..34360e7 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -772,8 +772,20 @@
      */
     @Override
     public boolean getValue(int index, TypedValue outValue) {
-        String s = getString(index);
-        return s != null && ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
+        // TODO: more switch cases for other types.
+        outValue.type = getType(index);
+        switch (outValue.type) {
+            case TYPE_NULL:
+                return false;
+            case TYPE_STRING:
+                outValue.string = getString(index);
+                return true;
+            default:
+                // For back-compatibility, parse as float.
+                String s = getString(index);
+                return s != null &&
+                        ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
+        }
     }
 
     @Override
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index 82b3792..31f01bd 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -128,8 +128,11 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (!mTerminated) {
+            if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
+            }
+
+            if (!mTerminated) {
                 destroy();
             }
         } finally {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 895defb..443db0c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -82,8 +82,11 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (!mTerminated) {
+            if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
+            }
+
+            if (!mTerminated) {
                 destroy();
             }
         } finally {