Merge "Disable WebView autocomplete feature." into oc-dev
diff --git a/Android.mk b/Android.mk
index 634272b..e27aa30 100644
--- a/Android.mk
+++ b/Android.mk
@@ -320,6 +320,8 @@
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
 	core/java/android/service/chooser/IChooserTargetService.aidl \
 	core/java/android/service/chooser/IChooserTargetResult.aidl \
+	core/java/android/service/resolver/IResolverRankerService.aidl \
+	core/java/android/service/resolver/IResolverRankerResult.aidl \
 	core/java/android/text/ITextClassificationService.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
@@ -367,7 +369,6 @@
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
 	core/java/com/android/internal/backup/IObbBackupService.aidl \
-	core/java/com/android/internal/font/IFontManager.aidl \
 	core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
 	core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
@@ -729,6 +730,7 @@
 	frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
+	frameworks/base/core/java/android/service/resolver/ResolverTarget.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/CacheQuotaHint.aidl \
 	frameworks/base/core/java/android/app/usage/ExternalStorageStats.aidl \
@@ -1461,8 +1463,7 @@
 LOCAL_SRC_FILES := \
     $(call all-proto-files-under, core/proto) \
     $(call all-proto-files-under, libs/incident/proto)
-LOCAL_SHARED_LIBRARIES := libprotobuf-cpp-full
-include $(BUILD_SHARED_LIBRARY)
+include $(BUILD_STATIC_LIBRARY)
 
 # ====  c++ proto host library  ==============================
 include $(CLEAR_VARS)
diff --git a/api/current.txt b/api/current.txt
index ff1d075..e640e30 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8889,7 +8889,6 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
-    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -10645,6 +10644,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";
@@ -13242,7 +13242,7 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -13776,8 +13776,8 @@
     method public static android.graphics.Typeface.Builder obtain();
     method public void recycle();
     method public void reset();
-    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
-    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
     method public android.graphics.Typeface.Builder setItalic(int);
     method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
     method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
@@ -14387,6 +14387,21 @@
     field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
   }
 
+  public final class FontVariationAxis implements android.os.Parcelable {
+    ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public int describeContents();
+    method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public float getStyleValue();
+    method public java.lang.String getTag();
+    method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR;
+  }
+
+  public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception {
+    ctor public FontVariationAxis.InvalidFormatException(java.lang.String);
+  }
+
 }
 
 package android.graphics.pdf {
@@ -15982,11 +15997,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);
   }
 
@@ -22999,6 +23014,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;
@@ -24540,85 +24556,6 @@
     field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
   }
 
-  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_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";
-    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
-    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final java.lang.String COLUMN_LIVE = "live";
-    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
-    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";
-  }
-
-  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-  }
-
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -24705,22 +24642,116 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
     field public static final android.net.Uri CONTENT_URI;
+    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 final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
     field public static final android.net.Uri CONTENT_URI;
@@ -24749,32 +24780,126 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
     ctor public TvContract.WatchNextPrograms();
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     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 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
+    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 {
@@ -41050,65 +41175,6 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
-  public final class FontConfig implements android.os.Parcelable {
-    ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]);
-    method public int describeContents();
-    method public android.text.FontConfig.Alias[] getAliases();
-    method public android.text.FontConfig.Family[] getFamilies();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
-  }
-
-  public static final class FontConfig.Alias implements android.os.Parcelable {
-    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
-    method public int describeContents();
-    method public java.lang.String getName();
-    method public java.lang.String getToName();
-    method public int getWeight();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
-  }
-
-  public static final class FontConfig.Axis implements android.os.Parcelable {
-    ctor public FontConfig.Axis(int, float);
-    ctor public FontConfig.Axis(java.lang.String, float);
-    method public int describeContents();
-    method public float getStyleValue();
-    method public int getTag();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
-  }
-
-  public static final class FontConfig.Family implements android.os.Parcelable {
-    ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int);
-    method public int describeContents();
-    method public android.text.FontConfig.Font[] getFonts();
-    method public java.lang.String getLanguage();
-    method public java.lang.String getName();
-    method public int getVariant();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
-    field public static final int VARIANT_COMPACT = 1; // 0x1
-    field public static final int VARIANT_DEFAULT = 0; // 0x0
-    field public static final int VARIANT_ELEGANT = 2; // 0x2
-  }
-
-  public static final class FontConfig.Font implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.text.FontConfig.Axis[] getAxes();
-    method public java.lang.String getFontName();
-    method public int getTtcIndex();
-    method public android.net.Uri getUri();
-    method public int getWeight();
-    method public boolean isItalic();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
-  }
-
-  public final class FontManager {
-    method public android.text.FontConfig getSystemFonts();
-  }
-
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -41256,6 +41322,8 @@
     field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
     field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
     field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
   }
 
   public static final class Layout.Alignment extends java.lang.Enum {
@@ -41457,7 +41525,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
-    method public android.text.StaticLayout.Builder setJustify(boolean);
+    method public android.text.StaticLayout.Builder setJustificationMode(int);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -51267,7 +51335,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
-    method public boolean getJustify();
+    method public int getJustificationMode();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -51362,7 +51430,7 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -51380,7 +51448,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
-    method public void setJustify(boolean);
+    method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 942668c..383b332 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -53,6 +53,7 @@
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+    field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
@@ -9386,7 +9387,6 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
-    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
@@ -11298,6 +11298,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";
@@ -13974,7 +13975,7 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -14508,8 +14509,8 @@
     method public static android.graphics.Typeface.Builder obtain();
     method public void recycle();
     method public void reset();
-    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
-    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
     method public android.graphics.Typeface.Builder setItalic(int);
     method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
     method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
@@ -15119,6 +15120,21 @@
     field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
   }
 
+  public final class FontVariationAxis implements android.os.Parcelable {
+    ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public int describeContents();
+    method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public float getStyleValue();
+    method public java.lang.String getTag();
+    method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR;
+  }
+
+  public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception {
+    ctor public FontVariationAxis.InvalidFormatException(java.lang.String);
+  }
+
 }
 
 package android.graphics.pdf {
@@ -17442,11 +17458,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);
   }
 
@@ -22841,6 +22857,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();
@@ -24792,6 +24809,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;
@@ -25842,8 +25860,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 {
@@ -25858,6 +25878,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;
   }
 
@@ -26481,85 +26502,6 @@
     field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
   }
 
-  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_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";
-    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
-    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final java.lang.String COLUMN_LIVE = "live";
-    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
-    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";
-  }
-
-  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-  }
-
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -26647,22 +26589,116 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
     field public static final android.net.Uri CONTENT_URI;
+    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 final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
     field public static final android.net.Uri CONTENT_URI;
@@ -26691,32 +26727,126 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
     ctor public TvContract.WatchNextPrograms();
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     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 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
+    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 {
@@ -40459,6 +40589,36 @@
 
 }
 
+package android.service.resolver {
+
+  public abstract class ResolverRankerService extends android.app.Service {
+    ctor public ResolverRankerService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>);
+    method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int);
+    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
+  }
+
+  public final class ResolverTarget implements android.os.Parcelable {
+    ctor public ResolverTarget();
+    method public int describeContents();
+    method public float getChooserScore();
+    method public float getLaunchScore();
+    method public float getRecencyScore();
+    method public float getSelectProbability();
+    method public float getTimeSpentScore();
+    method public void setChooserScore(float);
+    method public void setLaunchScore(float);
+    method public void setRecencyScore(float);
+    method public void setSelectProbability(float);
+    method public void setTimeSpentScore(float);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.resolver.ResolverTarget> CREATOR;
+  }
+
+}
+
 package android.service.restrictions {
 
   public abstract class RestrictionsReceiver extends android.content.BroadcastReceiver {
@@ -44508,65 +44668,6 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
-  public final class FontConfig implements android.os.Parcelable {
-    ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]);
-    method public int describeContents();
-    method public android.text.FontConfig.Alias[] getAliases();
-    method public android.text.FontConfig.Family[] getFamilies();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
-  }
-
-  public static final class FontConfig.Alias implements android.os.Parcelable {
-    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
-    method public int describeContents();
-    method public java.lang.String getName();
-    method public java.lang.String getToName();
-    method public int getWeight();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
-  }
-
-  public static final class FontConfig.Axis implements android.os.Parcelable {
-    ctor public FontConfig.Axis(int, float);
-    ctor public FontConfig.Axis(java.lang.String, float);
-    method public int describeContents();
-    method public float getStyleValue();
-    method public int getTag();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
-  }
-
-  public static final class FontConfig.Family implements android.os.Parcelable {
-    ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int);
-    method public int describeContents();
-    method public android.text.FontConfig.Font[] getFonts();
-    method public java.lang.String getLanguage();
-    method public java.lang.String getName();
-    method public int getVariant();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
-    field public static final int VARIANT_COMPACT = 1; // 0x1
-    field public static final int VARIANT_DEFAULT = 0; // 0x0
-    field public static final int VARIANT_ELEGANT = 2; // 0x2
-  }
-
-  public static final class FontConfig.Font implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.text.FontConfig.Axis[] getAxes();
-    method public java.lang.String getFontName();
-    method public int getTtcIndex();
-    method public android.net.Uri getUri();
-    method public int getWeight();
-    method public boolean isItalic();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
-  }
-
-  public final class FontManager {
-    method public android.text.FontConfig getSystemFonts();
-  }
-
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -44714,6 +44815,8 @@
     field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
     field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
     field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
   }
 
   public static final class Layout.Alignment extends java.lang.Enum {
@@ -44915,7 +45018,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
-    method public android.text.StaticLayout.Builder setJustify(boolean);
+    method public android.text.StaticLayout.Builder setJustificationMode(int);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -55093,7 +55196,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
-    method public boolean getJustify();
+    method public int getJustificationMode();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -55188,7 +55291,7 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -55206,7 +55309,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
-    method public void setJustify(boolean);
+    method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 16b3e50..795342f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8921,7 +8921,6 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
-    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -10684,6 +10683,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";
@@ -13292,7 +13292,7 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -13826,8 +13826,8 @@
     method public static android.graphics.Typeface.Builder obtain();
     method public void recycle();
     method public void reset();
-    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
-    method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
     method public android.graphics.Typeface.Builder setItalic(int);
     method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String);
     method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File);
@@ -14438,6 +14438,21 @@
     field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
   }
 
+  public final class FontVariationAxis implements android.os.Parcelable {
+    ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public int describeContents();
+    method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
+    method public float getStyleValue();
+    method public java.lang.String getTag();
+    method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR;
+  }
+
+  public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception {
+    ctor public FontVariationAxis.InvalidFormatException(java.lang.String);
+  }
+
 }
 
 package android.graphics.pdf {
@@ -16037,11 +16052,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);
   }
 
@@ -23112,6 +23127,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;
@@ -24653,85 +24669,6 @@
     field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
   }
 
-  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_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";
-    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
-    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final java.lang.String COLUMN_LIVE = "live";
-    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
-    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";
-  }
-
-  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-  }
-
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -24818,22 +24755,116 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
     field public static final android.net.Uri CONTENT_URI;
+    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 final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
     field public static final android.net.Uri CONTENT_URI;
@@ -24862,32 +24893,126 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+  public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
     ctor public TvContract.WatchNextPrograms();
+    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_AUDIO_LANGUAGE = "audio_language";
+    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_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    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_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final java.lang.String COLUMN_LIVE = "live";
+    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    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 COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     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 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
+    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 {
@@ -41258,65 +41383,6 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
-  public final class FontConfig implements android.os.Parcelable {
-    ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]);
-    method public int describeContents();
-    method public android.text.FontConfig.Alias[] getAliases();
-    method public android.text.FontConfig.Family[] getFamilies();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
-  }
-
-  public static final class FontConfig.Alias implements android.os.Parcelable {
-    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
-    method public int describeContents();
-    method public java.lang.String getName();
-    method public java.lang.String getToName();
-    method public int getWeight();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
-  }
-
-  public static final class FontConfig.Axis implements android.os.Parcelable {
-    ctor public FontConfig.Axis(int, float);
-    ctor public FontConfig.Axis(java.lang.String, float);
-    method public int describeContents();
-    method public float getStyleValue();
-    method public int getTag();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
-  }
-
-  public static final class FontConfig.Family implements android.os.Parcelable {
-    ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int);
-    method public int describeContents();
-    method public android.text.FontConfig.Font[] getFonts();
-    method public java.lang.String getLanguage();
-    method public java.lang.String getName();
-    method public int getVariant();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
-    field public static final int VARIANT_COMPACT = 1; // 0x1
-    field public static final int VARIANT_DEFAULT = 0; // 0x0
-    field public static final int VARIANT_ELEGANT = 2; // 0x2
-  }
-
-  public static final class FontConfig.Font implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.text.FontConfig.Axis[] getAxes();
-    method public java.lang.String getFontName();
-    method public int getTtcIndex();
-    method public android.net.Uri getUri();
-    method public int getWeight();
-    method public boolean isItalic();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
-  }
-
-  public final class FontManager {
-    method public android.text.FontConfig getSystemFonts();
-  }
-
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -41464,6 +41530,8 @@
     field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
     field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
     field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
+    field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
   }
 
   public static final class Layout.Alignment extends java.lang.Enum {
@@ -41665,7 +41733,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
-    method public android.text.StaticLayout.Builder setJustify(boolean);
+    method public android.text.StaticLayout.Builder setJustificationMode(int);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -51658,7 +51726,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
-    method public boolean getJustify();
+    method public int getJustificationMode();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -51753,7 +51821,7 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException;
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -51771,7 +51839,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
-    method public void setJustify(boolean);
+    method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
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/compiled-classes-phone b/compiled-classes-phone
index ea8f4a4..1a19b2c 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -4061,7 +4061,6 @@
 android.text.FontConfig$Family$1
 android.text.FontConfig$Font
 android.text.FontConfig$Font$1
-android.text.FontManager
 android.text.GetChars
 android.text.GraphicsOperations
 android.text.Html
@@ -5501,8 +5500,6 @@
 com.android.internal.content.PackageMonitor
 com.android.internal.content.ReferrerIntent
 com.android.internal.content.ReferrerIntent$1
-com.android.internal.font.IFontManager
-com.android.internal.font.IFontManager$Stub
 com.android.internal.graphics.drawable.AnimationScaleListDrawable
 com.android.internal.graphics.drawable.AnimationScaleListDrawable$AnimationScaleListState
 com.android.internal.hardware.AmbientDisplayConfiguration
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 5a7246a..75f9d67 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2218,6 +2218,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/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 279b900..399987f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1128,8 +1128,13 @@
             newState = Fragment.CREATED;
         }
         if (f.mRemoving && newState > f.mState) {
-            // While removing a fragment, we can't change it to a higher state.
-            newState = f.mState;
+            if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
+                // Allow the fragment to be created so that it can be saved later.
+                newState = Fragment.CREATED;
+            } else {
+                // While removing a fragment, we can't change it to a higher state.
+                newState = f.mState;
+            }
         }
         // Defer start if requested; don't allow it to move to STARTED or higher
         // if it's not already started.
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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f719749..6b05bdf 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -125,7 +125,6 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.text.FontManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -141,7 +140,6 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.app.ISoundTriggerService;
 import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.font.IFontManager;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.policy.PhoneLayoutInflater;
 
@@ -820,14 +818,6 @@
                 return new IncidentManager(ctx);
             }});
 
-        registerService(Context.FONT_SERVICE, FontManager.class,
-                new CachedServiceFetcher<FontManager>() {
-                    @Override
-                    public FontManager createService(ContextImpl ctx)
-                            throws ServiceNotFoundException {
-                        IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
-                        return new FontManager(IFontManager.Stub.asInterface(b));
-                    }});
         registerService(Context.AUTOFILL_MANAGER_SERVICE, AutofillManager.class,
                 new CachedServiceFetcher<AutofillManager>() {
             @Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dbbfe30..368c7b8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3870,11 +3870,6 @@
     public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
 
     /**
-     * Service that provides System font data.
-     */
-    public static final String FONT_SERVICE = "font";
-
-    /**
      * Service to report a system health "incident"
      * @hide
      */
@@ -4631,4 +4626,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/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 136c13b..a493f33 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2158,7 +2158,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/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/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index badb344..239a2df 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;
@@ -172,7 +174,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 +221,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 +262,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 +281,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 +334,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/com/android/internal/font/IFontManager.aidl b/core/java/android/service/resolver/IResolverRankerResult.aidl
similarity index 77%
copy from core/java/com/android/internal/font/IFontManager.aidl
copy to core/java/android/service/resolver/IResolverRankerResult.aidl
index 52a6262..bda3154 100644
--- a/core/java/com/android/internal/font/IFontManager.aidl
+++ b/core/java/android/service/resolver/IResolverRankerResult.aidl
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.font;
+package android.service.resolver;
 
-import android.text.FontConfig;
+import android.service.resolver.ResolverTarget;
 
 /**
- * Interface to the font manager.
  * @hide
  */
-interface IFontManager {
-    FontConfig getSystemFonts();
-}
+oneway interface IResolverRankerResult
+{
+    void sendResult(in List<ResolverTarget> results);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/android/service/resolver/IResolverRankerService.aidl
similarity index 65%
copy from core/java/com/android/internal/font/IFontManager.aidl
copy to core/java/android/service/resolver/IResolverRankerService.aidl
index 52a6262..f0d747d 100644
--- a/core/java/com/android/internal/font/IFontManager.aidl
+++ b/core/java/android/service/resolver/IResolverRankerService.aidl
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.internal.font;
+package android.service.resolver;
 
-import android.text.FontConfig;
+import android.service.resolver.IResolverRankerResult;
+import android.service.resolver.ResolverTarget;
 
 /**
- * Interface to the font manager.
  * @hide
  */
-interface IFontManager {
-    FontConfig getSystemFonts();
-}
+oneway interface IResolverRankerService
+{
+    void predict(in List<ResolverTarget> targets, IResolverRankerResult result);
+    void train(in List<ResolverTarget> targets, int selectedPosition);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resolver/ResolverRankerService.java b/core/java/android/service/resolver/ResolverRankerService.java
new file mode 100644
index 0000000..0506747
--- /dev/null
+++ b/core/java/android/service/resolver/ResolverRankerService.java
@@ -0,0 +1,187 @@
+/*
+ * 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.service.resolver;
+
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.service.resolver.ResolverTarget;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A service to rank apps according to usage stats of apps, when the system is resolving targets for
+ * an Intent.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE} permission, and include an
+ * intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ *     &lt;service android:name=".MyResolverRankerService"
+ *             android:exported="true"
+ *             android:priority="100"
+ *             android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"&gt;
+ *         &lt;intent-filter&gt;
+ *             &lt;action android:name="android.service.resolver.ResolverRankerService" /&gt;
+ *         &lt;/intent-filter&gt;
+ *     &lt;/service&gt;
+ * </pre>
+ * @hide
+ */
+@SystemApi
+public abstract class ResolverRankerService extends Service {
+
+    private static final String TAG = "ResolverRankerService";
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * The Intent action that a service must respond to. Add it to the intent filter of the service
+     * in its manifest.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
+
+    /**
+     * The permission that a service must require to ensure that only Android system can bind to it.
+     * If this permission is not enforced in the AndroidManifest of the service, the system will
+     * skip that service.
+     */
+    public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+
+    private ResolverRankerServiceWrapper mWrapper = null;
+
+    /**
+     * Called by the system to retrieve a list of probabilities to rank apps/options. To implement
+     * it, set selectProbability of each input {@link ResolverTarget}. The higher the
+     * selectProbability is, the more likely the {@link ResolverTarget} will be selected by the
+     * user. Override this function to provide prediction results.
+     *
+     * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
+     *
+     * @throws Exception when the prediction task fails.
+     */
+    public void onPredictSharingProbabilities(final List<ResolverTarget> targets) {}
+
+    /**
+     * Called by the system to train/update a ranking service, after the user makes a selection from
+     * the ranked list of apps. Override this function to enable model updates.
+     *
+     * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
+     * @param selectedPosition the position of the selected app in the list.
+     *
+     * @throws Exception when the training task fails.
+     */
+    public void onTrainRankingModel(
+            final List<ResolverTarget> targets, final int selectedPosition) {}
+
+    private static final String HANDLER_THREAD_NAME = "RESOLVER_RANKER_SERVICE";
+    private volatile Handler mHandler;
+    private HandlerThread mHandlerThread;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (DEBUG) Log.d(TAG, "onBind " + intent);
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null");
+            return null;
+        }
+        if (mHandlerThread == null) {
+            mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
+            mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
+        }
+        if (mWrapper == null) {
+            mWrapper = new ResolverRankerServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    @Override
+    public void onDestroy() {
+        mHandler = null;
+        if (mHandlerThread != null) {
+            mHandlerThread.quitSafely();
+        }
+        super.onDestroy();
+    }
+
+    private static void sendResult(List<ResolverTarget> targets, IResolverRankerResult result) {
+        try {
+            result.sendResult(targets);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to send results: " + e);
+        }
+    }
+
+    private class ResolverRankerServiceWrapper extends IResolverRankerService.Stub {
+
+        @Override
+        public void predict(final List<ResolverTarget> targets, final IResolverRankerResult result)
+                throws RemoteException {
+            Runnable predictRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "predict calls onPredictSharingProbabilities.");
+                        }
+                        onPredictSharingProbabilities(targets);
+                        sendResult(targets, result);
+                    } catch (Exception e) {
+                        Log.e(TAG, "onPredictSharingProbabilities failed; send null results: " + e);
+                        sendResult(null, result);
+                    }
+                }
+            };
+            final Handler h = mHandler;
+            if (h != null) {
+                h.post(predictRunnable);
+            }
+        }
+
+        @Override
+        public void train(final List<ResolverTarget> targets, final int selectedPosition)
+                throws RemoteException {
+            Runnable trainRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "train calls onTranRankingModel");
+                        }
+                        onTrainRankingModel(targets, selectedPosition);
+                    } catch (Exception e) {
+                        Log.e(TAG, "onTrainRankingModel failed; skip train: " + e);
+                    }
+                }
+            };
+            final Handler h = mHandler;
+            if (h != null) {
+                h.post(trainRunnable);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/android/service/resolver/ResolverTarget.aidl
similarity index 79%
rename from core/java/com/android/internal/font/IFontManager.aidl
rename to core/java/android/service/resolver/ResolverTarget.aidl
index 52a6262..6cab2d4 100644
--- a/core/java/com/android/internal/font/IFontManager.aidl
+++ b/core/java/android/service/resolver/ResolverTarget.aidl
@@ -14,14 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.internal.font;
-
-import android.text.FontConfig;
+package android.service.resolver;
 
 /**
- * Interface to the font manager.
  * @hide
  */
-interface IFontManager {
-    FontConfig getSystemFonts();
-}
+parcelable ResolverTarget;
diff --git a/core/java/android/service/resolver/ResolverTarget.java b/core/java/android/service/resolver/ResolverTarget.java
new file mode 100644
index 0000000..fb3e2d7
--- /dev/null
+++ b/core/java/android/service/resolver/ResolverTarget.java
@@ -0,0 +1,216 @@
+/*
+ * 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.service.resolver;
+
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * A ResolverTarget contains features by which an app or option will be ranked, in
+ * {@link ResolverRankerService}.
+ * @hide
+ */
+@SystemApi
+public final class ResolverTarget implements Parcelable {
+    private static final String TAG = "ResolverTarget";
+
+    /**
+     * a float score for recency of last use.
+     */
+    private float mRecencyScore;
+
+    /**
+     * a float score for total time spent.
+     */
+    private float mTimeSpentScore;
+
+    /**
+     * a float score for number of launches.
+     */
+    private float mLaunchScore;
+
+    /**
+     * a float score for number of selected.
+     */
+    private float mChooserScore;
+
+    /**
+     * a float score for the probability to be selected.
+     */
+    private float mSelectProbability;
+
+    // constructor for the class.
+    public ResolverTarget() {}
+
+    ResolverTarget(Parcel in) {
+        mRecencyScore = in.readFloat();
+        mTimeSpentScore = in.readFloat();
+        mLaunchScore = in.readFloat();
+        mChooserScore = in.readFloat();
+        mSelectProbability = in.readFloat();
+    }
+
+    /**
+     * Gets the score for how recently the target was used in the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more recently the
+     * target was used.
+     */
+    public float getRecencyScore() {
+        return mRecencyScore;
+    }
+
+    /**
+     * Sets the score for how recently the target was used in the foreground.
+     *
+     * @param recencyScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                     recently the target was used.
+     */
+    public void setRecencyScore(float recencyScore) {
+        this.mRecencyScore = recencyScore;
+    }
+
+    /**
+     * Gets the score for how long the target has been used in the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the longer the target
+     * has been used for.
+     */
+    public float getTimeSpentScore() {
+        return mTimeSpentScore;
+    }
+
+    /**
+     * Sets the score for how long the target has been used in the foreground.
+     *
+     * @param timeSpentScore a float score whose range is [0, 1]. The higher the score is, the
+     *                       longer the target has been used for.
+     */
+    public void setTimeSpentScore(float timeSpentScore) {
+        this.mTimeSpentScore = timeSpentScore;
+    }
+
+    /**
+     * Gets the score for how many times the target has been launched to the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more times the
+     * target has been launched.
+     */
+    public float getLaunchScore() {
+        return mLaunchScore;
+    }
+
+    /**
+     * Sets the score for how many times the target has been launched to the foreground.
+     *
+     * @param launchScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                    times the target has been launched.
+     */
+    public void setLaunchScore(float launchScore) {
+        this.mLaunchScore = launchScore;
+    }
+
+    /**
+     * Gets the score for how many times the target has been selected by the user to share the same
+     * types of content.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the
+     * more times the target has been selected by the user to share the same types of content for.
+     */
+    public float getChooserScore() {
+        return mChooserScore;
+    }
+
+    /**
+     * Sets the score for how many times the target has been selected by the user to share the same
+     * types of content.
+     *
+     * @param chooserScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                     times the target has been selected by the user to share the same types
+     *                     of content for.
+     */
+    public void setChooserScore(float chooserScore) {
+        this.mChooserScore = chooserScore;
+    }
+
+    /**
+     * Gets the probability of how likely this target will be selected by the user.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more likely the
+     * user is going to select this target.
+     */
+    public float getSelectProbability() {
+        return mSelectProbability;
+    }
+
+    /**
+     * Sets the probability for how like this target will be selected by the user.
+     *
+     * @param selectProbability a float score whose range is [0, 1]. The higher the score is, the
+     *                          more likely tht user is going to select this target.
+     */
+    public void setSelectProbability(float selectProbability) {
+        this.mSelectProbability = selectProbability;
+    }
+
+    // serialize the class to a string.
+    @Override
+    public String toString() {
+        return "ResolverTarget{"
+                + mRecencyScore + ", "
+                + mTimeSpentScore + ", "
+                + mLaunchScore + ", "
+                + mChooserScore + ", "
+                + mSelectProbability + "}";
+    }
+
+    // describes the kinds of special objects contained in this Parcelable instance's marshaled
+    // representation.
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // flattens this object in to a Parcel.
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeFloat(mRecencyScore);
+        dest.writeFloat(mTimeSpentScore);
+        dest.writeFloat(mLaunchScore);
+        dest.writeFloat(mChooserScore);
+        dest.writeFloat(mSelectProbability);
+    }
+
+    // creator definition for the class.
+    public static final Creator<ResolverTarget> CREATOR
+            = new Creator<ResolverTarget>() {
+        @Override
+        public ResolverTarget createFromParcel(Parcel source) {
+            return new ResolverTarget(source);
+        }
+
+        @Override
+        public ResolverTarget[] newArray(int size) {
+            return new ResolverTarget[size];
+        }
+    };
+}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 1e9deeb..6208c53 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -85,7 +85,7 @@
         this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
                 spacingmult, spacingadd, includepad,
                 StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE,
-                false /* justify */, ellipsize, ellipsizedWidth);
+                Layout.JUSTIFICATION_MODE_NONE, ellipsize, ellipsizedWidth);
     }
 
     /**
@@ -102,7 +102,7 @@
                          int width, Alignment align, TextDirectionHeuristic textDir,
                          float spacingmult, float spacingadd,
                          boolean includepad, int breakStrategy, int hyphenationFrequency,
-                         boolean justify, TextUtils.TruncateAt ellipsize,
+                         int justificationMode, TextUtils.TruncateAt ellipsize,
                          int ellipsizedWidth) {
         super((ellipsize == null)
                 ? display
@@ -128,7 +128,7 @@
 
         mIncludePad = includepad;
         mBreakStrategy = breakStrategy;
-        mJustify = justify;
+        mJustificationMode = justificationMode;
         mHyphenationFrequency = hyphenationFrequency;
 
         /*
@@ -303,7 +303,7 @@
                 .setEllipsize(mEllipsizeAt)
                 .setBreakStrategy(mBreakStrategy)
                 .setHyphenationFrequency(mHyphenationFrequency)
-                .setJustify(mJustify);
+                .setJustificationMode(mJustificationMode);
         reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
         // If the new layout has a blank line at the end, but it is not
@@ -811,7 +811,7 @@
     private TextUtils.TruncateAt mEllipsizeAt;
     private int mBreakStrategy;
     private int mHyphenationFrequency;
-    private boolean mJustify;
+    private int mJustificationMode;
 
     private PackedIntVector mInts;
     private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 14d3ad7..8537d8f 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -21,7 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.FontListParser;
+import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -31,6 +31,7 @@
 
 /**
  * Font configuration descriptions for System fonts.
+ * @hide
  */
 public final class FontConfig implements Parcelable {
     private final @NonNull Family[] mFamilies;
@@ -84,78 +85,12 @@
     };
 
     /**
-     * Class that holds information about a Font axis.
-     */
-    public static final class Axis implements Parcelable {
-        private final int mTag;
-        private final float mStyleValue;
-
-        public Axis(int tag, float styleValue) {
-            mTag = tag;
-            mStyleValue = styleValue;
-        }
-
-        public Axis(@NonNull String tagString, float styleValue) {
-            if (!FontListParser.isValidTag(tagString)) {
-                throw new IllegalArgumentException("Invalid tag pattern: " + tagString);
-            }
-            mTag = FontListParser.makeTag(tagString);
-            mStyleValue = styleValue;
-        }
-
-        /**
-         * Returns the variable font axis tag associated to this axis.
-         */
-        public int getTag() {
-            return mTag;
-        }
-
-        /**
-         * Returns the style value associated to the given axis for this font.
-         */
-        public float getStyleValue() {
-            return mStyleValue;
-        }
-
-        /**
-         * @hide
-         */
-        public Axis(Parcel in) {
-            mTag = in.readInt();
-            mStyleValue = in.readFloat();
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flag) {
-            out.writeInt(mTag);
-            out.writeFloat(mStyleValue);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<Axis> CREATOR = new Creator<Axis>() {
-            @Override
-            public Axis createFromParcel(Parcel in) {
-                return new Axis(in);
-            }
-
-            @Override
-            public Axis[] newArray(int size) {
-                return new Axis[size];
-            }
-        };
-    }
-
-    /**
      * Class that holds information about a Font.
      */
     public static final class Font implements Parcelable {
         private final @NonNull String mFontName;
         private final int mTtcIndex;
-        private final @NonNull Axis[] mAxes;
+        private final @NonNull FontVariationAxis[] mAxes;
         private final int mWeight;
         private final boolean mIsItalic;
         private Uri mUri;
@@ -163,8 +98,8 @@
         /**
          * @hide
          */
-        public Font(@NonNull String fontName, int ttcIndex, @NonNull Axis[] axes, int weight,
-                boolean isItalic) {
+        public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes,
+                int weight, boolean isItalic) {
             mFontName = fontName;
             mTtcIndex = ttcIndex;
             mAxes = axes;
@@ -189,7 +124,7 @@
         /**
          * Returns the list of axes associated to this font.
          */
-        public @NonNull Axis[] getAxes() {
+        public @NonNull FontVariationAxis[] getAxes() {
             return mAxes;
         }
 
@@ -230,7 +165,7 @@
         public Font(Parcel in) {
             mFontName = in.readString();
             mTtcIndex = in.readInt();
-            mAxes = in.createTypedArray(Axis.CREATOR);
+            mAxes = in.createTypedArray(FontVariationAxis.CREATOR);
             mWeight = in.readInt();
             mIsItalic = in.readInt() == 1;
             mUri = in.readTypedObject(Uri.CREATOR);
diff --git a/core/java/android/text/FontManager.java b/core/java/android/text/FontManager.java
deleted file mode 100644
index b61cbf3..0000000
--- a/core/java/android/text/FontManager.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.os.RemoteException;
-
-import com.android.internal.font.IFontManager;
-
-/**
- * Interact with the Font service.
- */
-public final class FontManager {
-    private static final String TAG = "FontManager";
-
-    private final IFontManager mService;
-
-    /**
-     * @hide
-     */
-    public FontManager(IFontManager service) {
-        mService = service;
-    }
-
-    /**
-     * Retrieve the system fonts data. This loads the fonts.xml data if needed and loads all system
-     * fonts in to memory, providing file descriptors for them.
-     */
-    public FontConfig getSystemFonts() {
-        try {
-            return mService.getSystemFonts();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-}
diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/android/text/FontVariationAxis.aidl
similarity index 64%
copy from core/java/com/android/internal/font/IFontManager.aidl
copy to core/java/android/text/FontVariationAxis.aidl
index 52a6262..d5d52c2 100644
--- a/core/java/com/android/internal/font/IFontManager.aidl
+++ b/core/java/android/text/FontVariationAxis.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.internal.font;
+package android.text;
 
-import android.text.FontConfig;
-
-/**
- * Interface to the font manager.
- * @hide
- */
-interface IFontManager {
-    FontConfig getSystemFonts();
-}
+parcelable FontVariationAxis;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 53564f0..b47fce8 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -103,6 +103,21 @@
     private static final ParagraphStyle[] NO_PARA_SPANS =
         ArrayUtils.emptyArray(ParagraphStyle.class);
 
+    /** @hide */
+    @IntDef({JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface JustificationMode {}
+
+    /**
+     * Value for justification mode indicating no justification.
+     */
+    public static final int JUSTIFICATION_MODE_NONE = 0;
+
+    /**
+     * Value for justification mode indicating the text is justified by stretching word spacing.
+     */
+    public static final int JUSTIFICATION_MODE_INTER_WORD = 1;
+
     /**
      * Return how wide a layout must be in order to display the specified text with one line per
      * paragraph.
@@ -219,8 +234,8 @@
     }
 
     /** @hide */
-    protected void setJustify(boolean justify) {
-        mJustify = justify;
+    protected void setJustificationMode(@JustificationMode int justificationMode) {
+        mJustificationMode = justificationMode;
     }
 
     /**
@@ -272,7 +287,7 @@
     }
 
     private boolean isJustificationRequired(int lineNum) {
-        if (!mJustify) return false;
+        if (mJustificationMode == JUSTIFICATION_MODE_NONE) return false;
         final int lineEnd = getLineEnd(lineNum);
         return lineEnd < mText.length() && mText.charAt(lineEnd - 1) != '\n';
     }
@@ -2229,7 +2244,7 @@
     private boolean mSpannedText;
     private TextDirectionHeuristic mTextDir;
     private SpanSet<LineBackgroundSpan> mLineBackgroundSpans;
-    private boolean mJustify;
+    private int mJustificationMode;
 
     public static final int DIR_LEFT_TO_RIGHT = 1;
     public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9a2e0bb..74ff6dc 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -94,7 +94,7 @@
             b.mMaxLines = Integer.MAX_VALUE;
             b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
             b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
-            b.mJustify = false;
+            b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
 
             b.mMeasuredText = MeasuredText.obtain();
             return b;
@@ -321,15 +321,15 @@
         }
 
         /**
-         * Enables or disables paragraph justification. The default value is disabled (false).
-         * If the last line is too short for justification, the last line will be displayed with
-         * the alignment set by {@link #setAlignment}.
+         * Set paragraph justification mode. The default value is
+         * {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification,
+         * the last line will be displayed with the alignment set by {@link #setAlignment}.
          *
-         * @param justify true for enabling and false for disabling paragraph justification.
+         * @param justificationMode justification mode for the paragraph.
          * @return this builder, useful for chaining.
          */
-        public Builder setJustify(boolean justify) {
-            mJustify = justify;
+        public Builder setJustificationMode(@JustificationMode int justificationMode) {
+            mJustificationMode = justificationMode;
             return this;
         }
 
@@ -418,7 +418,7 @@
         int mHyphenationFrequency;
         int[] mLeftIndents;
         int[] mRightIndents;
-        boolean mJustify;
+        int mJustificationMode;
 
         Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -572,7 +572,7 @@
 
         mLeftIndents = b.mLeftIndents;
         mRightIndents = b.mRightIndents;
-        setJustify(b.mJustify);
+        setJustificationMode(b.mJustificationMode);
 
         generate(b, b.mIncludePad, b.mIncludePad);
     }
@@ -693,7 +693,8 @@
             nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                     firstWidth, firstWidthLineCount, restWidth,
                     variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
-                    b.mJustify);
+                    // TODO: Support more justification mode, e.g. letter spacing, stretching.
+                    b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE);
             if (mLeftIndents != null || mRightIndents != null) {
                 // TODO(raph) performance: it would be better to do this once per layout rather
                 // than once per paragraph, but that would require a change to the native
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/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c250226..830f549 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7344,6 +7344,7 @@
 
     /** @hide */
     protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
+        requestLayout();
     }
 
     /** @hide */
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6f8df36..1b60ebc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -56,6 +56,7 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
+import android.graphics.fonts.FontVariationAxis;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -609,7 +610,7 @@
 
     private int mBreakStrategy;
     private int mHyphenationFrequency;
-    private boolean mJustify;
+    private int mJustificationMode;
 
     private int mMaximum = Integer.MAX_VALUE;
     private int mMaxMode = LINES;
@@ -820,7 +821,7 @@
         String fontFeatureSettings = null;
         mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
         mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
-        mJustify = false;
+        mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -3737,14 +3738,15 @@
     }
 
     /**
-     * Enables or disables full justification. The default value is false. If the last line is too
-     * short for justification, the last line will be displayed with the alignment set by
-     * {@link android.view.View#setTextAlignment}.
+     * Set justification mode. The default value is {@link Layout#JUSTIFICATION_MODE_NONE}. If the
+     * last line is too short for justification, the last line will be displayed with the
+     * alignment set by {@link android.view.View#setTextAlignment}.
      *
-     * @see #getJustify()
+     * @see #getJustificationMode()
      */
-    public void setJustify(boolean justify) {
-        mJustify = justify;
+    @Layout.JustificationMode
+    public void setJustificationMode(@Layout.JustificationMode int justificationMode) {
+        mJustificationMode = justificationMode;
         if (mLayout != null) {
             nullLayouts();
             requestLayout();
@@ -3753,12 +3755,12 @@
     }
 
     /**
-     * @return true if currently paragraph justification is enabled.
+     * @return true if currently paragraph justification mode.
      *
-     * @see #setJustify(boolean)
+     * @see #setJustificationMode(int)
      */
-    public boolean getJustify() {
-        return mJustify;
+    public @Layout.JustificationMode int getJustificationMode() {
+        return mJustificationMode;
     }
 
     /**
@@ -3808,10 +3810,14 @@
      *         TextView. This function also returns true for empty settings string. Otherwise
      *         returns false.
      *
+     * @throws FontVariationAxis.InvalidFormatException
+     *         If given string is not a valid font variation settings format.
+     *
      * @see #getFontVariationSettings()
      * @see Paint#getFontVariationSettings() Paint.getFontVariationSettings()
      */
-    public boolean setFontVariationSettings(@Nullable String fontVariationSettings) {
+    public boolean setFontVariationSettings(@Nullable String fontVariationSettings)
+            throws FontVariationAxis.InvalidFormatException {
         final String existingSettings = mTextPaint.getFontVariationSettings();
         if (fontVariationSettings == existingSettings
                 || (fontVariationSettings != null
@@ -7678,7 +7684,7 @@
                         .setIncludePad(mIncludePad)
                         .setBreakStrategy(mBreakStrategy)
                         .setHyphenationFrequency(mHyphenationFrequency)
-                        .setJustify(mJustify)
+                        .setJustificationMode(mJustificationMode)
                         .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
                 if (shouldEllipsize) {
                     builder.setEllipsize(mEllipsize)
@@ -7720,7 +7726,7 @@
         if (mText instanceof Spannable) {
             result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
                     alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
-                    mBreakStrategy, mHyphenationFrequency, mJustify,
+                    mBreakStrategy, mHyphenationFrequency, mJustificationMode,
                     getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
@@ -7770,7 +7776,7 @@
                     .setIncludePad(mIncludePad)
                     .setBreakStrategy(mBreakStrategy)
                     .setHyphenationFrequency(mHyphenationFrequency)
-                    .setJustify(mJustify)
+                    .setJustificationMode(mJustificationMode)
                     .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
             if (shouldEllipsize) {
                 builder.setEllipsize(effectiveEllipsize)
@@ -8110,7 +8116,7 @@
                     .setIncludePad(getIncludeFontPadding())
                     .setBreakStrategy(getBreakStrategy())
                     .setHyphenationFrequency(getHyphenationFrequency())
-                    .setJustify(getJustify())
+                    .setJustificationMode(getJustificationMode())
                     .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                     .setTextDirection(getTextDirectionHeuristic());
 
diff --git a/core/java/com/android/internal/app/LRResolverRankerService.java b/core/java/com/android/internal/app/LRResolverRankerService.java
new file mode 100644
index 0000000..1cad7c7
--- /dev/null
+++ b/core/java/com/android/internal/app/LRResolverRankerService.java
@@ -0,0 +1,199 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.storage.StorageManager;
+import android.service.resolver.ResolverRankerService;
+import android.service.resolver.ResolverTarget;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used
+ * in {@link ResolverComparator}.
+ */
+public final class LRResolverRankerService extends ResolverRankerService {
+    private static final String TAG = "LRResolverRankerService";
+
+    private static final boolean DEBUG = false;
+
+    private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
+    private static final String BIAS_PREF_KEY = "bias";
+    private static final String VERSION_PREF_KEY = "version";
+
+    private static final String LAUNCH_SCORE = "launch";
+    private static final String TIME_SPENT_SCORE = "timeSpent";
+    private static final String RECENCY_SCORE = "recency";
+    private static final String CHOOSER_SCORE = "chooser";
+
+    // parameters for a pre-trained model, to initialize the app ranker. When updating the
+    // pre-trained model, please update these params, as well as initModel().
+    private static final int CURRENT_VERSION = 1;
+    private static final float LEARNING_RATE = 0.0001f;
+    private static final float REGULARIZER_PARAM = 0.0001f;
+
+    private SharedPreferences mParamSharedPref;
+    private ArrayMap<String, Float> mFeatureWeights;
+    private float mBias;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        initModel();
+        return super.onBind(intent);
+    }
+
+    @Override
+    public void onPredictSharingProbabilities(List<ResolverTarget> targets) {
+        final int size = targets.size();
+        for (int i = 0; i < size; ++i) {
+            ResolverTarget target = targets.get(i);
+            ArrayMap<String, Float> features = getFeatures(target);
+            target.setSelectProbability(predict(features));
+        }
+    }
+
+    @Override
+    public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) {
+        final int size = targets.size();
+        if (selectedPosition < 0 || selectedPosition >= size) {
+            if (DEBUG) {
+                Log.d(TAG, "Invalid Position of Selected App " + selectedPosition);
+            }
+            return;
+        }
+        final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition));
+        final float positiveProbability = targets.get(selectedPosition).getSelectProbability();
+        final int targetSize = targets.size();
+        for (int i = 0; i < targetSize; ++i) {
+            if (i == selectedPosition) {
+                continue;
+            }
+            final ArrayMap<String, Float> negative = getFeatures(targets.get(i));
+            final float negativeProbability = targets.get(i).getSelectProbability();
+            if (negativeProbability > positiveProbability) {
+                update(negative, negativeProbability, false);
+                update(positive, positiveProbability, true);
+            }
+        }
+        commitUpdate();
+    }
+
+    private void initModel() {
+        mParamSharedPref = getParamSharedPref();
+        mFeatureWeights = new ArrayMap<>(4);
+        if (mParamSharedPref == null ||
+                mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
+            // Initializing the app ranker to a pre-trained model. When updating the pre-trained
+            // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
+            // REGULARIZER_PARAM.
+            mBias = -1.6568f;
+            mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
+            mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
+            mFeatureWeights.put(RECENCY_SCORE, 0.269f);
+            mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
+        } else {
+            mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
+            mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
+            mFeatureWeights.put(
+                    TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
+            mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
+            mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
+        }
+    }
+
+    private ArrayMap<String, Float> getFeatures(ResolverTarget target) {
+        ArrayMap<String, Float> features = new ArrayMap<>(4);
+        features.put(RECENCY_SCORE, target.getRecencyScore());
+        features.put(TIME_SPENT_SCORE, target.getTimeSpentScore());
+        features.put(LAUNCH_SCORE, target.getLaunchScore());
+        features.put(CHOOSER_SCORE, target.getChooserScore());
+        return features;
+    }
+
+    private float predict(ArrayMap<String, Float> target) {
+        if (target == null) {
+            return 0.0f;
+        }
+        final int featureSize = target.size();
+        float sum = 0.0f;
+        for (int i = 0; i < featureSize; i++) {
+            String featureName = target.keyAt(i);
+            float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+            sum += weight * target.valueAt(i);
+        }
+        return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
+    }
+
+    private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
+        if (target == null) {
+            return;
+        }
+        final int featureSize = target.size();
+        float error = isSelected ? 1.0f - predict : -predict;
+        for (int i = 0; i < featureSize; i++) {
+            String featureName = target.keyAt(i);
+            float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+            mBias += LEARNING_RATE * error;
+            currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
+                    LEARNING_RATE * error * target.valueAt(i);
+            mFeatureWeights.put(featureName, currentWeight);
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
+        }
+    }
+
+    private void commitUpdate() {
+        try {
+            SharedPreferences.Editor editor = mParamSharedPref.edit();
+            editor.putFloat(BIAS_PREF_KEY, mBias);
+            final int size = mFeatureWeights.size();
+            for (int i = 0; i < size; i++) {
+                editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
+            }
+            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
+            editor.apply();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to commit update" + e);
+        }
+    }
+
+    private SharedPreferences getParamSharedPref() {
+        // The package info in the context isn't initialized in the way it is for normal apps,
+        // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
+        // build the path manually below using the same policy that appears in ContextImpl.
+        if (DEBUG) {
+            Log.d(TAG, "Context Package Name: " + getPackageName());
+        }
+        final File prefsFile = new File(new File(
+                Environment.getDataUserCePackageDirectory(
+                        StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
+                "shared_prefs"),
+                PARAM_SHARED_PREF_NAME + ".xml");
+        return getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3f1c9ad..622b708 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -530,6 +530,9 @@
             getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
             mPostListReadyRunnable = null;
         }
+        if (mAdapter != null && mAdapter.mResolverListController != null) {
+            mAdapter.mResolverListController.destroy();
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 096fcb8..73b62a5 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -26,20 +26,34 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.SharedPreferences;
+import android.content.ServiceConnection;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
 import android.os.storage.StorageManager;
 import android.os.UserHandle;
+import android.service.resolver.IResolverRankerService;
+import android.service.resolver.IResolverRankerResult;
+import android.service.resolver.ResolverRankerService;
+import android.service.resolver.ResolverTarget;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 
 import java.io.File;
+import java.lang.InterruptedException;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -61,11 +75,15 @@
 
     private static final float RECENCY_MULTIPLIER = 2.f;
 
-    // feature names used in ranking.
-    private static final String LAUNCH_SCORE = "launch";
-    private static final String TIME_SPENT_SCORE = "timeSpent";
-    private static final String RECENCY_SCORE = "recency";
-    private static final String CHOOSER_SCORE = "chooser";
+    // message types
+    private static final int RESOLVER_RANKER_SERVICE_RESULT = 0;
+    private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1;
+
+    // timeout for establishing connections with a ResolverRankerService.
+    private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
+    // timeout for establishing connections with a ResolverRankerService, collecting features and
+    // predicting ranking scores.
+    private static final int WATCHDOG_TIMEOUT_MILLIS = 500;
 
     private final Collator mCollator;
     private final boolean mHttp;
@@ -74,18 +92,74 @@
     private final Map<String, UsageStats> mStats;
     private final long mCurrentTime;
     private final long mSinceTime;
-    private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
+    private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>();
     private final String mReferrerPackage;
+    private final Object mLock = new Object();
+    private ArrayList<ResolverTarget> mTargets;
     private String mContentType;
     private String[] mAnnotations;
     private String mAction;
-    private LogisticRegressionAppRanker mRanker;
+    private IResolverRankerService mRanker;
+    private ResolverRankerServiceConnection mConnection;
+    private AfterCompute mAfterCompute;
+    private Context mContext;
+    private CountDownLatch mConnectSignal;
 
-    public ResolverComparator(Context context, Intent intent, String referrerPackage) {
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case RESOLVER_RANKER_SERVICE_RESULT:
+                    if (DEBUG) {
+                        Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT");
+                    }
+                    if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) {
+                        if (msg.obj != null) {
+                            final List<ResolverTarget> receivedTargets =
+                                    (List<ResolverTarget>) msg.obj;
+                            if (receivedTargets != null && mTargets != null
+                                    && receivedTargets.size() == mTargets.size()) {
+                                final int size = mTargets.size();
+                                for (int i = 0; i < size; ++i) {
+                                    mTargets.get(i).setSelectProbability(
+                                            receivedTargets.get(i).getSelectProbability());
+                                }
+                            } else {
+                                Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
+                            }
+                        } else {
+                            Log.e(TAG, "Receiving null prediction results.");
+                        }
+                        mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
+                        mAfterCompute.afterCompute();
+                    }
+                    break;
+
+                case RESOLVER_RANKER_RESULT_TIMEOUT:
+                    if (DEBUG) {
+                        Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services");
+                    }
+                    mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
+                    mAfterCompute.afterCompute();
+                    break;
+
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    };
+
+    public interface AfterCompute {
+        public void afterCompute ();
+    }
+
+    public ResolverComparator(Context context, Intent intent, String referrerPackage,
+                              AfterCompute afterCompute) {
         mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
         String scheme = intent.getScheme();
         mHttp = "http".equals(scheme) || "https".equals(scheme);
         mReferrerPackage = referrerPackage;
+        mAfterCompute = afterCompute;
+        mContext = context;
 
         mPm = context.getPackageManager();
         mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
@@ -96,9 +170,9 @@
         mContentType = intent.getType();
         getContentAnnotations(intent);
         mAction = intent.getAction();
-        mRanker = new LogisticRegressionAppRanker(context);
     }
 
+    // get annotations of content from intent.
     public void getContentAnnotations(Intent intent) {
         ArrayList<String> annotations = intent.getStringArrayListExtra(
                 Intent.EXTRA_CONTENT_ANNOTATIONS);
@@ -114,20 +188,24 @@
         }
     }
 
+    public void setCallBack(AfterCompute afterCompute) {
+        mAfterCompute = afterCompute;
+    }
+
+    // compute features for each target according to usage stats of targets.
     public void compute(List<ResolvedComponentInfo> targets) {
-        mScoredTargets.clear();
+        reset();
 
         final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
 
-        long mostRecentlyUsedTime = recentSinceTime + 1;
-        long mostTimeSpent = 1;
-        int mostLaunched = 1;
-        int mostSelected = 1;
+        float mostRecencyScore = 1.0f;
+        float mostTimeSpentScore = 1.0f;
+        float mostLaunchScore = 1.0f;
+        float mostChooserScore = 1.0f;
 
         for (ResolvedComponentInfo target : targets) {
-            final ScoredTarget scoredTarget
-                    = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
-            mScoredTargets.put(target.name, scoredTarget);
+            final ResolverTarget resolverTarget = new ResolverTarget();
+            mTargetsDict.put(target.name, resolverTarget);
             final UsageStats pkStats = mStats.get(target.name.getPackageName());
             if (pkStats != null) {
                 // Only count recency for apps that weren't the caller
@@ -135,31 +213,33 @@
                 // Persistent processes muck this up, so omit them too.
                 if (!target.name.getPackageName().equals(mReferrerPackage)
                         && !isPersistentProcess(target)) {
-                    final long lastTimeUsed = pkStats.getLastTimeUsed();
-                    scoredTarget.lastTimeUsed = lastTimeUsed;
-                    if (lastTimeUsed > mostRecentlyUsedTime) {
-                        mostRecentlyUsedTime = lastTimeUsed;
+                    final float recencyScore =
+                            (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
+                    resolverTarget.setRecencyScore(recencyScore);
+                    if (recencyScore > mostRecencyScore) {
+                        mostRecencyScore = recencyScore;
                     }
                 }
-                final long timeSpent = pkStats.getTotalTimeInForeground();
-                scoredTarget.timeSpent = timeSpent;
-                if (timeSpent > mostTimeSpent) {
-                    mostTimeSpent = timeSpent;
+                final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
+                resolverTarget.setTimeSpentScore(timeSpentScore);
+                if (timeSpentScore > mostTimeSpentScore) {
+                    mostTimeSpentScore = timeSpentScore;
                 }
-                final int launched = pkStats.mLaunchCount;
-                scoredTarget.launchCount = launched;
-                if (launched > mostLaunched) {
-                    mostLaunched = launched;
+                final float launchScore = (float) pkStats.mLaunchCount;
+                resolverTarget.setLaunchScore(launchScore);
+                if (launchScore > mostLaunchScore) {
+                    mostLaunchScore = launchScore;
                 }
 
-                int selected = 0;
+                float chooserScore = 0.0f;
                 if (pkStats.mChooserCounts != null && mAction != null
                         && pkStats.mChooserCounts.get(mAction) != null) {
-                    selected = pkStats.mChooserCounts.get(mAction).getOrDefault(mContentType, 0);
+                    chooserScore = (float) pkStats.mChooserCounts.get(mAction)
+                            .getOrDefault(mContentType, 0);
                     if (mAnnotations != null) {
                         final int size = mAnnotations.length;
                         for (int i = 0; i < size; i++) {
-                            selected += pkStats.mChooserCounts.get(mAction)
+                            chooserScore += (float) pkStats.mChooserCounts.get(mAction)
                                     .getOrDefault(mAnnotations[i], 0);
                         }
                     }
@@ -169,44 +249,37 @@
                         Log.d(TAG, "Action type is null");
                     } else {
                         Log.d(TAG, "Chooser Count of " + mAction + ":" +
-                                target.name.getPackageName() + " is " + Integer.toString(selected));
+                                target.name.getPackageName() + " is " +
+                                Float.toString(chooserScore));
                     }
                 }
-                scoredTarget.chooserCount = selected;
-                if (selected > mostSelected) {
-                    mostSelected = selected;
+                resolverTarget.setChooserScore(chooserScore);
+                if (chooserScore > mostChooserScore) {
+                    mostChooserScore = chooserScore;
                 }
             }
         }
 
-
         if (DEBUG) {
-            Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
-                    + " mostTimeSpent: " + mostTimeSpent
-                    + " recentSinceTime: " + recentSinceTime
-                    + " mostLaunched: " + mostLaunched);
+            Log.d(TAG, "compute - mostRecencyScore: " + mostRecencyScore
+                    + " mostTimeSpentScore: " + mostTimeSpentScore
+                    + " mostLaunchScore: " + mostLaunchScore
+                    + " mostChooserScore: " + mostChooserScore);
         }
 
-        for (ScoredTarget target : mScoredTargets.values()) {
-            final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
-                    / (mostRecentlyUsedTime - recentSinceTime);
-            target.setFeatures((float) target.launchCount / mostLaunched,
-                    (float) target.timeSpent / mostTimeSpent,
-                    recency * recency * RECENCY_MULTIPLIER,
-                    (float) target.chooserCount / mostSelected);
-            target.selectProb = mRanker.predict(target.getFeatures());
+        mTargets = new ArrayList<>(mTargetsDict.values());
+        for (ResolverTarget target : mTargets) {
+            final float recency = target.getRecencyScore() / mostRecencyScore;
+            setFeatures(target, recency * recency * RECENCY_MULTIPLIER,
+                    target.getLaunchScore() / mostLaunchScore,
+                    target.getTimeSpentScore() / mostTimeSpentScore,
+                    target.getChooserScore() / mostChooserScore);
+            addDefaultSelectProbability(target);
             if (DEBUG) {
                 Log.d(TAG, "Scores: " + target);
             }
         }
-    }
-
-    static boolean isPersistentProcess(ResolvedComponentInfo rci) {
-        if (rci != null && rci.getCount() > 0) {
-            return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
-                    ApplicationInfo.FLAG_PERSISTENT) != 0;
-        }
-        return false;
+        predictSelectProbabilities(mTargets);
     }
 
     @Override
@@ -245,16 +318,16 @@
         // Pinned items stay stable within a normal lexical sort and ignore scoring.
         if (!lPinned && !rPinned) {
             if (mStats != null) {
-                final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
+                final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
                         lhs.activityInfo.packageName, lhs.activityInfo.name));
-                final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
+                final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
                         rhs.activityInfo.packageName, rhs.activityInfo.name));
 
-                final int selectProbDiff = Float.compare(
-                        rhsTarget.selectProb, lhsTarget.selectProb);
+                final int selectProbabilityDiff = Float.compare(
+                        rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
 
-                if (selectProbDiff != 0) {
-                    return selectProbDiff > 0 ? 1 : -1;
+                if (selectProbabilityDiff != 0) {
+                    return selectProbabilityDiff > 0 ? 1 : -1;
                 }
             }
         }
@@ -268,177 +341,234 @@
     }
 
     public float getScore(ComponentName name) {
-        final ScoredTarget target = mScoredTargets.get(name);
+        final ResolverTarget target = mTargetsDict.get(name);
         if (target != null) {
-            return target.selectProb;
+            return target.getSelectProbability();
         }
         return 0;
     }
 
-    static class ScoredTarget {
-        public final ComponentInfo componentInfo;
-        public long lastTimeUsed;
-        public long timeSpent;
-        public long launchCount;
-        public long chooserCount;
-        public ArrayMap<String, Float> features;
-        public float selectProb;
-
-        public ScoredTarget(ComponentInfo ci) {
-            componentInfo = ci;
-            features = new ArrayMap<>(5);
-        }
-
-        @Override
-        public String toString() {
-            return "ScoredTarget{" + componentInfo
-                    + " lastTimeUsed: " + lastTimeUsed
-                    + " timeSpent: " + timeSpent
-                    + " launchCount: " + launchCount
-                    + " chooserCount: " + chooserCount
-                    + " selectProb: " + selectProb
-                    + "}";
-        }
-
-        public void setFeatures(float launchCountScore, float usageTimeScore, float recencyScore,
-                                float chooserCountScore) {
-            features.put(LAUNCH_SCORE, launchCountScore);
-            features.put(TIME_SPENT_SCORE, usageTimeScore);
-            features.put(RECENCY_SCORE, recencyScore);
-            features.put(CHOOSER_SCORE, chooserCountScore);
-        }
-
-        public ArrayMap<String, Float> getFeatures() {
-            return features;
-        }
-    }
-
     public void updateChooserCounts(String packageName, int userId, String action) {
         if (mUsm != null) {
             mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
         }
     }
 
+    // update ranking model when the connection to it is valid.
     public void updateModel(ComponentName componentName) {
-        if (mScoredTargets == null || componentName == null ||
-                !mScoredTargets.containsKey(componentName)) {
-            return;
-        }
-        ScoredTarget selected = mScoredTargets.get(componentName);
-        for (ComponentName targetComponent : mScoredTargets.keySet()) {
-            if (targetComponent.equals(componentName)) {
-                continue;
-            }
-            ScoredTarget target = mScoredTargets.get(targetComponent);
-            // A potential point of optimization. Save updates or derive a closed form for the
-            // positive case, to avoid calculating them repeatedly.
-            if (target.selectProb >= selected.selectProb) {
-                mRanker.update(target.getFeatures(), target.selectProb, false);
-                mRanker.update(selected.getFeatures(), selected.selectProb, true);
+        synchronized (mLock) {
+            if (mRanker != null) {
+                try {
+                    int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
+                            .indexOf(componentName);
+                    if (selectedPos > 0) {
+                        mRanker.train(mTargets, selectedPos);
+                    } else {
+                        if (DEBUG) {
+                            Log.d(TAG, "Selected a unknown component: " + componentName);
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in Train: " + e);
+                }
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Ranker is null; skip updateModel.");
+                }
             }
         }
-        mRanker.commitUpdate();
     }
 
-    class LogisticRegressionAppRanker {
-        private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
-        private static final String BIAS_PREF_KEY = "bias";
-        private static final String VERSION_PREF_KEY = "version";
-
-        // parameters for a pre-trained model, to initialize the app ranker. When updating the
-        // pre-trained model, please update these params, as well as initModel().
-        private static final int CURRENT_VERSION = 1;
-        private static final float LEARNING_RATE = 0.0001f;
-        private static final float REGULARIZER_PARAM = 0.0001f;
-
-        private SharedPreferences mParamSharedPref;
-        private ArrayMap<String, Float> mFeatureWeights;
-        private float mBias;
-
-        public LogisticRegressionAppRanker(Context context) {
-            mParamSharedPref = getParamSharedPref(context);
-            initModel();
+    // unbind the service and clear unhandled messges.
+    public void destroy() {
+        mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
+        mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
+        if (mConnection != null) {
+            mContext.unbindService(mConnection);
+            mConnection.destroy();
         }
-
-        public float predict(ArrayMap<String, Float> target) {
-            if (target == null) {
-                return 0.0f;
-            }
-            final int featureSize = target.size();
-            float sum = 0.0f;
-            for (int i = 0; i < featureSize; i++) {
-                String featureName = target.keyAt(i);
-                float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-                sum += weight * target.valueAt(i);
-            }
-            return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
+        if (DEBUG) {
+            Log.d(TAG, "Unbinded Resolver Ranker.");
         }
+    }
 
-        public void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
-            if (target == null) {
+    // connect to a ranking service.
+    private void initRanker(Context context) {
+        synchronized (mLock) {
+            if (mConnection != null && mRanker != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Ranker still exists; reusing the existing one.");
+                }
                 return;
             }
-            final int featureSize = target.size();
-            float error = isSelected ? 1.0f - predict : -predict;
-            for (int i = 0; i < featureSize; i++) {
-                String featureName = target.keyAt(i);
-                float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-                mBias += LEARNING_RATE * error;
-                currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
-                        LEARNING_RATE * error * target.valueAt(i);
-                mFeatureWeights.put(featureName, currentWeight);
+        }
+        Intent intent = resolveRankerService();
+        if (intent == null) {
+            return;
+        }
+        mConnectSignal = new CountDownLatch(1);
+        mConnection = new ResolverRankerServiceConnection(mConnectSignal);
+        context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+    }
+
+    // resolve the service for ranking.
+    private Intent resolveRankerService() {
+        Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE);
+        final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0);
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            if (resolveInfo == null || resolveInfo.serviceInfo == null
+                    || resolveInfo.serviceInfo.applicationInfo == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Failed to retrieve a ranker: " + resolveInfo);
+                }
+                continue;
+            }
+            ComponentName componentName = new ComponentName(
+                    resolveInfo.serviceInfo.applicationInfo.packageName,
+                    resolveInfo.serviceInfo.name);
+            try {
+                final String perm = mPm.getServiceInfo(componentName, 0).permission;
+                if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
+                    Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
+                            + " permission " + ResolverRankerService.BIND_PERMISSION
+                            + " - this service will not be queried for ResolverComparator."
+                            + " add android:permission=\""
+                            + ResolverRankerService.BIND_PERMISSION + "\""
+                            + " to the <service> tag for " + componentName
+                            + " in the manifest.");
+                    continue;
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Could not look up service " + componentName
+                        + "; component name not found");
+                continue;
             }
             if (DEBUG) {
-                Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
+                Log.d(TAG, "Succeeded to retrieve a ranker: " + componentName);
             }
+            intent.setComponent(componentName);
+            return intent;
+        }
+        return null;
+    }
+
+    // set a watchdog, to avoid waiting for ranking service for too long.
+    private void startWatchDog(int timeOutLimit) {
+        if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms");
+        if (mHandler == null) {
+            Log.d(TAG, "Error: Handler is Null; Needs to be initialized.");
+        }
+        mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit);
+    }
+
+    private class ResolverRankerServiceConnection implements ServiceConnection {
+        private final CountDownLatch mConnectSignal;
+
+        public ResolverRankerServiceConnection(CountDownLatch connectSignal) {
+            mConnectSignal = connectSignal;
         }
 
-        public void commitUpdate() {
-            SharedPreferences.Editor editor = mParamSharedPref.edit();
-            editor.putFloat(BIAS_PREF_KEY, mBias);
-            final int size = mFeatureWeights.size();
-            for (int i = 0; i < size; i++) {
-                editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
+        public final IResolverRankerResult resolverRankerResult =
+                new IResolverRankerResult.Stub() {
+            @Override
+            public void sendResult(List<ResolverTarget> targets) throws RemoteException {
+                if (DEBUG) {
+                    Log.d(TAG, "Sending Result back to Resolver: " + targets);
+                }
+                synchronized (mLock) {
+                    final Message msg = Message.obtain();
+                    msg.what = RESOLVER_RANKER_SERVICE_RESULT;
+                    msg.obj = targets;
+                    mHandler.sendMessage(msg);
+                }
             }
-            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
-            editor.apply();
-        }
+        };
 
-        private SharedPreferences getParamSharedPref(Context context) {
-            // The package info in the context isn't initialized in the way it is for normal apps,
-            // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
-            // build the path manually below using the same policy that appears in ContextImpl.
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) {
-                Log.d(TAG, "Context Package Name: " + context.getPackageName());
+                Log.d(TAG, "onServiceConnected: " + name);
             }
-            final File prefsFile = new File(new File(
-                    Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
-                            context.getUserId(), context.getPackageName()),
-                    "shared_prefs"),
-                    PARAM_SHARED_PREF_NAME + ".xml");
-            return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+            synchronized (mLock) {
+                mRanker = IResolverRankerService.Stub.asInterface(service);
+                mConnectSignal.countDown();
+            }
         }
 
-        private void initModel() {
-            mFeatureWeights = new ArrayMap<>(4);
-            if (mParamSharedPref == null ||
-                    mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
-                // Initializing the app ranker to a pre-trained model. When updating the pre-trained
-                // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
-                // REGULARIZER_PARAM.
-                mBias = -1.6568f;
-                mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
-                mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
-                mFeatureWeights.put(RECENCY_SCORE, 0.269f);
-                mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
-            } else {
-                mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
-                mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
-                mFeatureWeights.put(
-                        TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
-                mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
-                mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) {
+                Log.d(TAG, "onServiceDisconnected: " + name);
+            }
+            synchronized (mLock) {
+                destroy();
             }
         }
+
+        public void destroy() {
+            synchronized (mLock) {
+                mRanker = null;
+            }
+        }
+    }
+
+    private void reset() {
+        mTargetsDict.clear();
+        mTargets = null;
+        startWatchDog(WATCHDOG_TIMEOUT_MILLIS);
+        initRanker(mContext);
+    }
+
+    // predict select probabilities if ranking service is valid.
+    private void predictSelectProbabilities(List<ResolverTarget> targets) {
+        if (mConnection == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction");
+            }
+            return;
+        } else {
+            try {
+                mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+                synchronized (mLock) {
+                    if (mRanker != null) {
+                        mRanker.predict(targets, mConnection.resolverRankerResult);
+                        return;
+                    } else {
+                        if (DEBUG) {
+                            Log.d(TAG, "Ranker has not been initialized; skip predict.");
+                        }
+                    }
+                }
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Error in Wait for Service Connection.");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in Predict: " + e);
+            }
+        }
+        mAfterCompute.afterCompute();
+    }
+
+    // adds select prob as the default values, according to a pre-trained Logistic Regression model.
+    private void addDefaultSelectProbability(ResolverTarget target) {
+        float sum = 2.5543f * target.getLaunchScore() + 2.8412f * target.getTimeSpentScore() +
+                0.269f * target.getRecencyScore() + 4.2222f * target.getChooserScore();
+        target.setSelectProbability((float) (1.0 / (1.0 + Math.exp(1.6568f - sum))));
+    }
+
+    // sets features for each target
+    private void setFeatures(ResolverTarget target, float recencyScore, float launchScore,
+                             float timeSpentScore, float chooserScore) {
+        target.setRecencyScore(recencyScore);
+        target.setLaunchScore(launchScore);
+        target.setTimeSpentScore(timeSpentScore);
+        target.setChooserScore(chooserScore);
+    }
+
+    static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+        if (rci != null && rci.getCount() > 0) {
+            return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+                    ApplicationInfo.FLAG_PERSISTENT) != 0;
+        }
+        return false;
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 4071ff4..e8bebb7 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -32,8 +32,10 @@
 import android.util.Log;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.InterruptedException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
 import java.util.List;
 
 /**
@@ -205,14 +207,42 @@
         return listToReturn;
     }
 
+    private class ComputeCallback implements ResolverComparator.AfterCompute {
+
+        private CountDownLatch mFinishComputeSignal;
+
+        public ComputeCallback(CountDownLatch finishComputeSignal) {
+            mFinishComputeSignal = finishComputeSignal;
+        }
+
+        public void afterCompute () {
+            mFinishComputeSignal.countDown();
+        }
+    }
+
     @VisibleForTesting
     @WorkerThread
     public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
+        final CountDownLatch finishComputeSignal = new CountDownLatch(1);
+        ComputeCallback callback = new ComputeCallback(finishComputeSignal);
         if (mResolverComparator == null) {
-            mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
+            mResolverComparator =
+                    new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, callback);
+        } else {
+            mResolverComparator.setCallBack(callback);
         }
-        mResolverComparator.compute(inputList);
-        Collections.sort(inputList, mResolverComparator);
+        try {
+            long beforeRank = System.currentTimeMillis();
+            mResolverComparator.compute(inputList);
+            finishComputeSignal.await();
+            Collections.sort(inputList, mResolverComparator);
+            long afterRank = System.currentTimeMillis();
+            if (DEBUG) {
+                Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Compute & Sort was interrupted: " + e);
+        }
     }
 
     private static boolean isSameResolvedComponent(ResolveInfo a,
@@ -233,7 +263,7 @@
     @VisibleForTesting
     public float getScore(ResolverActivity.DisplayResolveInfo target) {
         if (mResolverComparator == null) {
-            mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
+            return 0.0f;
         }
         return mResolverComparator.getScore(target.getResolvedComponentName());
     }
@@ -249,4 +279,10 @@
             mResolverComparator.updateChooserCounts(packageName, userId, action);
         }
     }
+
+    public void destroy() {
+        if (mResolverComparator != null) {
+            mResolverComparator.destroy();
+        }
+    }
 }
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/graphics/FontUtils.cpp b/core/jni/android/graphics/FontUtils.cpp
index 91fec2a..3bcf0c7 100644
--- a/core/jni/android/graphics/FontUtils.cpp
+++ b/core/jni/android/graphics/FontUtils.cpp
@@ -55,7 +55,7 @@
     gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
     gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
 
-    jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
+    jclass axisClass = FindClassOrDie(env, "android/graphics/fonts/FontVariationAxis");
     gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
     gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
 }
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index a77ed62..1a35330 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -10,6 +10,14 @@
 
 using namespace android::uirenderer;
 
+/**
+ * By default Skia gradients will interpolate their colors in unpremul space
+ * and then premultiply each of the results. We must set this flag to preserve
+ * backwards compatiblity by premultiplying the colors of the gradient first,
+ * and then interpolating between them.
+ */
+static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
+
 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     if (NULL == ptr) {
         doThrowIAE(env);
@@ -89,7 +97,7 @@
 
     SkShader* shader = SkGradientShader::MakeLinear(pts,
             reinterpret_cast<const SkColor*>(colorValues), pos, count,
-            static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
 
     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
     ThrowIAE_IfNull(env, shader);
@@ -109,7 +117,7 @@
     colors[1] = color1;
 
     SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2,
-            (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
 
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
@@ -135,7 +143,7 @@
 
     SkShader* shader = SkGradientShader::MakeRadial(center, radius,
             reinterpret_cast<const SkColor*>(colorValues), pos, count,
-            static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
                                  JNI_ABORT);
 
@@ -154,7 +162,7 @@
     colors[1] = color1;
 
     SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
-            (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
 }
@@ -174,8 +182,8 @@
     #error Need to convert float array to SkScalar array before calling the following function.
 #endif
 
-    SkShader* shader = SkGradientShader::MakeSweep(x, y,
-            reinterpret_cast<const SkColor*>(colors), pos, count, /* flags */ 0, matrix).release();
+    SkShader* shader = SkGradientShader::MakeSweep(x, y, reinterpret_cast<const SkColor*>(colors),
+            pos, count, sGradientShaderFlags, matrix).release();
     env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
                                  JNI_ABORT);
     ThrowIAE_IfNull(env, shader);
@@ -189,7 +197,7 @@
     colors[0] = color0;
     colors[1] = color1;
     SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2,
-            /* flags */ 0, matrix).release();
+            sGradientShaderFlags, matrix).release();
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
 }
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 713287e..5839fd5 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/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0ab27f2..b95258b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -346,6 +346,11 @@
         return false;
     }
 
+    // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
+    if (mount_mode == MOUNT_EXTERNAL_NONE) {
+        return true;
+    }
+
     if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
             NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
         ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 3f1bdff..2641ab8 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -69,6 +69,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 ffcb8476..0a50048 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3129,6 +3129,15 @@
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Must be required by services that extend
+         {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+         bind to them.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
@@ -3346,7 +3355,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" />
@@ -3360,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.CHOOSE_ACCESSIBILITY_BUTTON" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3421,7 +3432,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"
@@ -3429,14 +3441,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"
@@ -3450,7 +3464,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"
@@ -3634,6 +3649,14 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.internal.app.LRResolverRankerService"
+            android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+            android:exported="false"
+            android:priority="-1" >
+            <intent-filter>
+                <action android:name="android.service.resolver.ResolverRankerService" />
+            </intent-filter>
+        </service>
     </application>
 
 </manifest>
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/tests/coretests/src/android/graphics/VariationParserTest.java b/core/tests/coretests/src/android/graphics/VariationParserTest.java
deleted file mode 100644
index fdabb13..0000000
--- a/core/tests/coretests/src/android/graphics/VariationParserTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.FontConfig;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-
-
-public class VariationParserTest extends TestCase {
-
-    @SmallTest
-    public void testParseFontVariationSetting() {
-        int tag = FontListParser.makeTag("wdth");
-        List<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings("'wdth' 1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("\"wdth\" 100");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(100.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("   'wdth' 100");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(100.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(0.5f, axes.get(0).getStyleValue());
-
-        tag = FontListParser.makeTag("AX  ");
-        axes = FontListParser.parseFontVariationSettings("'AX  ' 1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("'AX  '\t1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("'AX  '\n1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("'AX  '\r1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        axes = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
-        assertEquals(tag, axes.get(0).getTag());
-        assertEquals(1.0f, axes.get(0).getStyleValue());
-
-        // Test for invalid input
-        axes = FontListParser.parseFontVariationSettings("");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("invalid_form");
-        assertEquals(0, axes.size());
-
-        // Test with invalid tag
-        axes = FontListParser.parseFontVariationSettings("'' 1");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'invalid' 1");
-        assertEquals(0, axes.size());
-
-        // Test with invalid styleValue
-        axes = FontListParser.parseFontVariationSettings("'wdth' ");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' x");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' \t");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' \n\r");
-        assertEquals(0, axes.size());
-    }
-
-    @SmallTest
-    public void testParseFontVariationStyleSettings() {
-        List<FontConfig.Axis> axes =
-                FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
-        int tag1 = FontListParser.makeTag("wdth");
-        int tag2 = FontListParser.makeTag("AX  ");
-        assertEquals(tag1, axes.get(0).getTag());
-        assertEquals(10.0f, axes.get(0).getStyleValue());
-        assertEquals(tag2, axes.get(1).getTag());
-        assertEquals(1.0f, axes.get(1).getStyleValue());
-
-        // Test only spacers are allowed before tag
-        axes = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
-        tag1 = FontListParser.makeTag("wdth");
-        assertEquals(tag1, axes.get(0).getTag());
-        assertEquals(10.0f, axes.get(0).getStyleValue());
-        assertEquals(1, axes.size());
-    }
-
-    @SmallTest
-    public void testInvalidTagCharacters() {
-        List<FontConfig.Axis> axes =
-                FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
-        assertEquals(0, axes.size());
-    }
-
-    @SmallTest
-    public void testMakeTag() {
-      assertEquals(0x77647468, FontListParser.makeTag("wdth"));
-      assertEquals(0x41582020, FontListParser.makeTag("AX  "));
-      assertEquals(0x20202020, FontListParser.makeTag("    "));
-    }
-}
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
new file mode 100644
index 0000000..bcc47e1
--- /dev/null
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.graphics.fonts.FontVariationAxis;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class VariationParserTest extends TestCase {
+    private static final String[] INVALID_STYLE_VALUES = {
+        "", "x", "\t", "\n"
+    };
+
+    @SmallTest
+    public void testFromFontVariationSetting_InvalidStyleValue() {
+        // Test with invalid styleValue
+        for (String invalidStyle : INVALID_STYLE_VALUES) {
+            try {
+                FontVariationAxis.fromFontVariationSettings("'wdth' " + invalidStyle);
+                fail();
+            } catch (FontVariationAxis.InvalidFormatException e) {
+                // pass
+            }
+        }
+        for (String invalidStyle : INVALID_STYLE_VALUES) {
+            try {
+                FontVariationAxis.fromFontVariationSettings("'wght' 1, 'wdth' " + invalidStyle);
+                fail();
+            } catch (FontVariationAxis.InvalidFormatException e) {
+                // pass
+            }
+        }
+    }
+
+    @SmallTest
+    public void testOpenTypeTagValue() throws FontVariationAxis.InvalidFormatException {
+      assertEquals(0x77647468, (new FontVariationAxis("wdth", 0).getOpenTypeTagValue()));
+      assertEquals(0x41582020, (new FontVariationAxis("AX  ", 0).getOpenTypeTagValue()));
+      assertEquals(0x20202020, (new FontVariationAxis("    ", 0).getOpenTypeTagValue()));
+    }
+}
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/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 76c29a9..3dab1f7 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -3,15 +3,10 @@
     WARNING: Parsing of this file by third-party apps is not supported. The
     file, and the font files it refers to, will be renamed and/or moved out
     from their respective location in the next Android release, and/or the
-    format or syntax of the file may change significantly. You must not
-    parse this file for information about system fonts. Instead, you must
-    call android.text.FontManager#getSystemFonts(). For example, it can be
-    called as context.getSystemService(FontManager.class).getSystemFonts().
-    Note that the returned FontConfig includes data on all the defined font
-    families and all the details about weight, style, etc. It also provides
-    an open file descriptor to each font file. Note that callers of the API
-    should ensure they close the given file descriptors once they are done
-    using them.
+    format or syntax of the file may change significantly. If you parse this
+    file for information about system fonts, do it at your own risk. Your
+    application will almost certainly break with the next major Android
+    release.
 
     In this file, all fonts without names are added to the default list.
     Fonts are chosen based on a match: full BCP-47 language tag including
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 6214ba6..4b1b0c6 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import android.content.res.AssetManager;
+import android.graphics.fonts.FontVariationAxis;
 import android.text.FontConfig;
 import android.util.Log;
 import dalvik.annotation.optimization.CriticalNative;
@@ -81,7 +82,7 @@
         }
     }
 
-    public boolean addFont(String path, int ttcIndex, FontConfig.Axis[] axes, int weight,
+    public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight,
             int italic) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFont after freezing.");
@@ -91,8 +92,8 @@
             long fontSize = fileChannel.size();
             ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
             if (axes != null) {
-                for (FontConfig.Axis axis : axes) {
-                    nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+                for (FontVariationAxis axis : axes) {
+                    nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue());
                 }
             }
             return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic);
@@ -102,14 +103,14 @@
         }
     }
 
-    public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontConfig.Axis[] axes,
+    public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes,
             int weight, int italic) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFontWeightStyle after freezing.");
         }
         if (axes != null) {
-            for (FontConfig.Axis axis : axes) {
-                nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+            for (FontVariationAxis axis : axes) {
+                nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue());
             }
         }
         return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, italic);
@@ -129,13 +130,13 @@
      */
     public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
             boolean isAsset, int ttcIndex, int weight, int isItalic,
-            FontConfig.Axis[] axes) {
+            FontVariationAxis[] axes) {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("Unable to call addFontFromAsset after freezing.");
         }
         if (axes != null) {
-            for (FontConfig.Axis axis : axes) {
-                nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue());
+            for (FontVariationAxis axis : axes) {
+                nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue());
             }
         }
         return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, ttcIndex, weight,
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index ff9f11d..1a4f225 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import android.text.FontConfig;
+import android.graphics.fonts.FontVariationAxis;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -50,72 +51,6 @@
         }
     }
 
-    // Note that a well-formed variation contains a four-character tag and a float as styleValue,
-    // with spacers in between. The tag is enclosd either by double quotes or single quotes.
-    @VisibleForTesting
-    public static ArrayList<FontConfig.Axis> parseFontVariationSettings(@Nullable String settings) {
-        ArrayList<FontConfig.Axis> axisList = new ArrayList<>();
-        if (settings == null) {
-            return axisList;
-        }
-        String[] settingList = settings.split(",");
-        settingLoop:
-        for (String setting : settingList) {
-            int pos = 0;
-            while (pos < setting.length()) {
-                char c = setting.charAt(pos);
-                if (c == '\'' || c == '"') {
-                    break;
-                } else if (!isSpacer(c)) {
-                    continue settingLoop;  // Only spacers are allowed before tag appeared.
-                }
-                pos++;
-            }
-            if (pos + 7 > setting.length()) {
-                continue;  // 7 is the minimum length of tag-style value pair text.
-            }
-            if (setting.charAt(pos) != setting.charAt(pos + 5)) {
-                continue;  // Tag should be wrapped with double or single quote.
-            }
-            String tagString = setting.substring(pos + 1, pos + 5);
-            if (!TAG_PATTERN.matcher(tagString).matches()) {
-                continue;  // Skip incorrect format tag.
-            }
-            pos += 6;
-            while (pos < setting.length()) {
-                if (!isSpacer(setting.charAt(pos++))) {
-                    break;  // Skip spacers between the tag and the styleValue.
-                }
-            }
-            // Skip invalid styleValue
-            float styleValue;
-            String valueString = setting.substring(pos - 1);
-            if (!STYLE_VALUE_PATTERN.matcher(valueString).matches()) {
-                continue;  // Skip incorrect format styleValue.
-            }
-            try {
-                styleValue = Float.parseFloat(valueString);
-            } catch (NumberFormatException e) {
-                continue;  // ignoreing invalid number format
-            }
-            int tag = makeTag(tagString);
-            axisList.add(new FontConfig.Axis(tag, styleValue));
-        }
-        return axisList;
-    }
-
-    public static int makeTag(String tagString) {
-        char c1 = tagString.charAt(0);
-        char c2 = tagString.charAt(1);
-        char c3 = tagString.charAt(2);
-        char c4 = tagString.charAt(3);
-        return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
-    }
-
-    private static boolean isSpacer(char c) {
-        return c == ' ' || c == '\r' || c == '\t' || c == '\n';
-    }
-
     private static FontConfig readFamilies(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         List<FontConfig.Family> families = new ArrayList<>();
@@ -172,7 +107,7 @@
             throws XmlPullParserException, IOException {
         String indexStr = parser.getAttributeValue(null, "index");
         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
-        List<FontConfig.Axis> axes = new ArrayList<FontConfig.Axis>();
+        List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
         String weightStr = parser.getAttributeValue(null, "weight");
         int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
         boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
@@ -191,47 +126,20 @@
         }
         String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
         return new FontConfig.Font(sanitizedName, index,
-                axes.toArray(new FontConfig.Axis[axes.size()]), weight, isItalic);
+                axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic);
     }
 
-    /** The 'tag' attribute value is read as four character values between U+0020 and U+007E
-     *  inclusive.
-     */
-    private static final Pattern TAG_PATTERN = Pattern.compile("[\\x20-\\x7E]{4}");
-
-    public static boolean isValidTag(String tagString) {
-        if (tagString == null || tagString.length() != 4) {
-            return false;
-        }
-        return TAG_PATTERN.matcher(tagString).matches();
-    }
-
-    /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
-     *  '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
-     */
-    private static final Pattern STYLE_VALUE_PATTERN =
-            Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
-
-    private static FontConfig.Axis readAxis(XmlPullParser parser)
+    private static FontVariationAxis readAxis(XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
-        if (isValidTag(tagStr)) {
-            tag = makeTag(tagStr);
-        } else {
-            throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
-        }
-
-        float styleValue = 0;
         String styleValueStr = parser.getAttributeValue(null, "stylevalue");
-        if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) {
-            styleValue = Float.parseFloat(styleValueStr);
-        } else {
-            throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null);
-        }
-
         skip(parser);  // axis tag is empty, ignore any contents and consume end tag
-        return new FontConfig.Axis(tag, styleValue);
+        try {
+            return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr));
+        } catch (FontVariationAxis.InvalidFormatException e) {
+            // Treat as system failure since system preinstalled font setting has invalid format.
+            throw new RuntimeException(e);
+        }
     }
 
     private static FontConfig.Alias readAlias(XmlPullParser parser)
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index c4f7dc3..828729a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Size;
 import android.graphics.FontListParser;
+import android.graphics.fonts.FontVariationAxis;
 import android.os.LocaleList;
 import android.text.FontConfig;
 import android.text.GraphicsOperations;
@@ -1551,8 +1552,11 @@
      * @return true if the given settings is effective to at least one font file underlying this
      *         typeface. This function also returns true for empty settings string. Otherwise
      *         returns false
+     * @throws FontVariationAxis.InvalidFormatException
+     *         If given string is not a valid font variation settings format.
      */
-    public boolean setFontVariationSettings(String settings) {
+    public boolean setFontVariationSettings(String settings)
+            throws FontVariationAxis.InvalidFormatException {
         settings = TextUtils.nullIfEmpty(settings);
         if (settings == mFontVariationSettings
                 || (settings != null && settings.equals(mFontVariationSettings))) {
@@ -1566,11 +1570,10 @@
             return true;
         }
 
-        final ArrayList<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings(settings);
-        final ArrayList<FontConfig.Axis> filteredAxes = new ArrayList<FontConfig.Axis>();
-        for (int i = 0; i < axes.size(); ++i) {
-            final FontConfig.Axis axis = axes.get(i);
-            if (mTypeface.isSupportedAxes(axis.getTag())) {
+        FontVariationAxis[] axes = FontVariationAxis.fromFontVariationSettings(settings);
+        final ArrayList<FontVariationAxis> filteredAxes = new ArrayList<FontVariationAxis>();
+        for (final FontVariationAxis axis : axes) {
+            if (mTypeface.isSupportedAxes(axis.getOpenTypeTagValue())) {
                 filteredAxes.add(axis);
             }
         }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 8c3a2e8..560d29f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -32,6 +32,7 @@
 import android.graphics.FontListParser;
 import android.graphics.fonts.FontRequest;
 import android.graphics.fonts.FontResult;
+import android.graphics.fonts.FontVariationAxis;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
@@ -358,11 +359,15 @@
                         FileChannel.MapMode.READ_ONLY, 0, fontSize);
                 int style = result.getStyle();
                 int weight = (style & BOLD) != 0 ? 700 : 400;
-                final ArrayList<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings(
-                        result.getFontVariationSettings());
-                if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(),
-                                axes.toArray(new FontConfig.Axis[axes.size()]), weight,
-                                (style & ITALIC) == 0 ? Builder.NORMAL : Builder.ITALIC)) {
+                FontVariationAxis[] axes = null;
+                try {
+                    axes = FontVariationAxis.fromFontVariationSettings(
+                            result.getFontVariationSettings());
+                } catch (FontVariationAxis.InvalidFormatException e) {
+                    // TODO: Nice to pass FontVariationAxis[] directly instead of string.
+                }
+                if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(), axes, weight,
+                        (style & ITALIC) == 0 ? Builder.NORMAL : Builder.ITALIC)) {
                     Log.e(TAG, "Error creating font " + request.getQuery());
                     callback.onTypefaceRequestFailed(
                             FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
@@ -514,7 +519,7 @@
         public static final int ITALIC = 1;
 
         private int mTtcIndex;
-        private FontConfig.Axis[] mAxes;
+        private FontVariationAxis[] mAxes;
 
         private AssetManager mAssetManager;
         private String mPath;
@@ -682,15 +687,16 @@
          * Sets a font variation settings.
          *
          * @param variationSettings See {@link android.widget.TextView#setFontVariationSettings}.
+         * @throws FontVariationAxis.InvalidFormatException If given string is not a valid font
+         *                                                  variation settings format.
          */
-        public Builder setFontVariationSettings(@Nullable String variationSettings) {
+        public Builder setFontVariationSettings(@Nullable String variationSettings)
+                throws FontVariationAxis.InvalidFormatException {
             checkNotRecycled();
             if (mAxes != null) {
                 throw new IllegalStateException("Font variation settings are already set.");
             }
-            final List<FontConfig.Axis> axesList = FontListParser.parseFontVariationSettings(
-                    variationSettings);
-            mAxes = axesList.toArray(new FontConfig.Axis[axesList.size()]);
+            mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings);
             return this;
         }
 
@@ -699,7 +705,7 @@
          *
          * @param axes An array of font variation axis tag-value pairs.
          */
-        public Builder setFontVariationSettings(@Nullable FontConfig.Axis[] axes) {
+        public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) {
             checkNotRecycled();
             if (mAxes != null) {
                 throw new IllegalStateException("Font variation settings are already set.");
@@ -718,7 +724,7 @@
          * @return Unique id for a given AssetManager and asset path.
          */
         private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex,
-                @Nullable FontConfig.Axis[] axes) {
+                @Nullable FontVariationAxis[] axes) {
             final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
             final StringBuilder builder = new StringBuilder();
             final int size = pkgs.size();
@@ -731,8 +737,8 @@
             builder.append(Integer.toString(ttcIndex));
             builder.append("-");
             if (axes != null) {
-                for (FontConfig.Axis axis : axes) {
-                    builder.append(Integer.toHexString(axis.getTag()));
+                for (FontVariationAxis axis : axes) {
+                    builder.append(axis.getTag());
                     builder.append("-");
                     builder.append(Float.toString(axis.getStyleValue()));
                 }
@@ -865,7 +871,7 @@
 
     /** @hide */
     public static Typeface createFromTypefaceWithVariation(Typeface family,
-            List<FontConfig.Axis> axes) {
+            List<FontVariationAxis> axes) {
         final long ni = family == null ? 0 : family.native_instance;
         return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes));
     }
@@ -1162,9 +1168,9 @@
     }
 
     private static native long nativeCreateFromTypeface(long native_instance, int style);
-    // TODO: clean up: change List<FontConfig.Axis> to FontConfig.Axis[]
+    // TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[]
     private static native long nativeCreateFromTypefaceWithVariation(
-            long native_instance, List<FontConfig.Axis> axes);
+            long native_instance, List<FontVariationAxis> axes);
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 04864bdc..a491d7e 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -88,9 +88,7 @@
     }
 
     @Override
-    public
-    @Config
-    int getChangingConfigurations() {
+    public @Config int getChangingConfigurations() {
         return super.getChangingConfigurations()
                 | mDrawableContainerState.getChangingConfigurations();
     }
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 322e55b..b159f0f 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -32,6 +32,7 @@
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 
@@ -66,6 +67,8 @@
  * @attr ref android.R.styleable#LayerDrawableItem_id
 */
 public class LayerDrawable extends Drawable implements Drawable.Callback {
+    private static final String LOG_TAG = "LayerDrawable";
+
     /**
      * Padding mode used to nest each layer inside the padding of the previous
      * layer.
@@ -89,6 +92,7 @@
      */
     public static final int INSET_UNDEFINED = Integer.MIN_VALUE;
 
+    @NonNull
     LayerState mLayerState;
 
     private int[] mPaddingL;
@@ -170,13 +174,9 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        final LayerState state = mLayerState;
-        if (state == null) {
-            return;
-        }
-
         // The density may have changed since the last update. This will
         // apply scaling to any existing constant state properties.
+        final LayerState state = mLayerState;
         final int density = Drawable.resolveDensity(r, 0);
         state.setDensity(density);
 
@@ -202,10 +202,6 @@
         super.applyTheme(t);
 
         final LayerState state = mLayerState;
-        if (state == null) {
-            return;
-        }
-
         final int density = Drawable.resolveDensity(t.getResources(), 0);
         state.setDensity(density);
 
@@ -403,7 +399,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
+        return mLayerState.canApplyTheme() || super.canApplyTheme();
     }
 
     /**
@@ -1841,15 +1837,24 @@
                 final ConstantState cs = dr.getConstantState();
                 if (cs == null) {
                     clone = dr;
+                    if (dr.getCallback() != null) {
+                        // This drawable already has an owner.
+                        Log.w(LOG_TAG, "Invalid drawable added to LayerDrawable! Drawable already "
+                                + "belongs to another owner but does not expose a constant state.",
+                                new RuntimeException());
+                    }
                 } else if (res != null) {
                     clone = cs.newDrawable(res);
                 } else {
                     clone = cs.newDrawable();
                 }
-                clone.setCallback(owner);
                 clone.setLayoutDirection(dr.getLayoutDirection());
                 clone.setBounds(dr.getBounds());
                 clone.setLevel(dr.getLevel());
+
+                // Set the callback last to prevent invalidation from
+                // propagating before the constant state has been set.
+                clone.setCallback(owner);
             } else {
                 clone = null;
             }
diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java
new file mode 100644
index 0000000..91ec0e8
--- /dev/null
+++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java
@@ -0,0 +1,230 @@
+/*
+ * 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.graphics.fonts;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+/**
+ * Class that holds information about single font variation axis.
+ */
+public final class FontVariationAxis implements Parcelable {
+    private final int mTag;
+    private final String mTagString;
+    private final float mStyleValue;
+
+    /**
+     * Construct FontVariationAxis.
+     *
+     * The axis tag must contain four ASCII characters. Tag string that are longer or shorter than
+     * four characters, or contains characters outside of U+0020..U+007E are invalid.
+     *
+     * @throws {@link InvalidFormatException} If given tag string is invalid.
+     */
+    public FontVariationAxis(@NonNull String tagString, float styleValue)
+            throws InvalidFormatException {
+        if (!isValidTag(tagString)) {
+            throw new InvalidFormatException("Invalid tag pattern: " + tagString);
+        }
+        mTag = makeTag(tagString);
+        mTagString = tagString;
+        mStyleValue = styleValue;
+    }
+
+    /**
+     * Returns the OpenType style tag value.
+     * @hide
+     */
+    public int getOpenTypeTagValue() {
+        return mTag;
+    }
+
+    /**
+     * Returns the variable font axis tag associated to this axis.
+     */
+    public String getTag() {
+        return mTagString;
+    }
+
+    /**
+     * Returns the style value associated to the given axis for this font.
+     */
+    public float getStyleValue() {
+        return mStyleValue;
+    }
+
+    /**
+     * @hide
+     */
+    public FontVariationAxis(Parcel in) {
+        mTag = in.readInt();
+        mTagString = in.readString();
+        mStyleValue = in.readFloat();
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flag) {
+        out.writeInt(mTag);
+        out.writeString(mTagString);
+        out.writeFloat(mStyleValue);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<FontVariationAxis> CREATOR = new Creator<FontVariationAxis>() {
+        @Override
+        public FontVariationAxis createFromParcel(Parcel in) {
+            return new FontVariationAxis(in);
+        }
+
+        @Override
+        public FontVariationAxis[] newArray(int size) {
+            return new FontVariationAxis[size];
+        }
+    };
+
+    /**
+     * Returns a valid font variation setting string for this object.
+     */
+    @Override
+    public @NonNull String toString() {
+        return "'" + mTagString + "' " + Float.toString(mStyleValue);
+    }
+
+    /**
+     * The 'tag' attribute value is read as four character values between U+0020 and U+007E
+     * inclusive.
+     */
+    private static final Pattern TAG_PATTERN = Pattern.compile("[\u0020-\u007E]{4}");
+
+    /**
+     * Returns true if 'tagString' is valid for font variation axis tag.
+     */
+    private static boolean isValidTag(String tagString) {
+        return tagString != null && TAG_PATTERN.matcher(tagString).matches();
+    }
+
+    /**
+     * The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
+     * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
+     */
+    private static final Pattern STYLE_VALUE_PATTERN =
+            Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
+
+    private static boolean isValidValueFormat(String valueString) {
+        return valueString != null && STYLE_VALUE_PATTERN.matcher(valueString).matches();
+    }
+
+    /** @hide */
+    public static int makeTag(String tagString) {
+        final char c1 = tagString.charAt(0);
+        final char c2 = tagString.charAt(1);
+        final char c3 = tagString.charAt(2);
+        final char c4 = tagString.charAt(3);
+        return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
+    }
+
+    /**
+     * An exception indicates that the format of font variation settings is invalid.
+     */
+    public static class InvalidFormatException extends Exception {
+        public InvalidFormatException(String message) {
+            super(message);
+        }
+    };
+
+    /**
+     * Construct FontVariationAxis array from font variation settings.
+     *
+     * The settings string is constructed from multiple pairs of axis tag and style values. The axis
+     * tag must contain four ASCII characters and must be wrapped with single quotes (U+0027) or
+     * double quotes (U+0022). Axis strings that are longer or shorter than four characters, or
+     * contain characters outside of U+0020..U+007E are invalid. If a specified axis name is not
+     * defined in the font, the settings will be ignored.
+     *
+     * <pre>
+     *   FontVariationAxis.fromFontVariationSettings("'wdth' 1.0");
+     *   FontVariationAxis.fromFontVariationSettings("'AX  ' 1.0, 'FB  ' 2.0");
+     * </pre>
+     *
+     * @param settings font variation settings.
+     * @return FontVariationAxis[] the array of parsed font variation axis. {@code null} if settings
+     *                             has no font variation settings.
+     * @throws InvalidFormatException If given string is not a valid font variation settings format.
+     */
+    public static @Nullable FontVariationAxis[] fromFontVariationSettings(@Nullable String settings)
+            throws InvalidFormatException {
+        if (settings == null || settings.isEmpty()) {
+            return null;
+        }
+        final ArrayList<FontVariationAxis> axisList = new ArrayList<>();
+        final int length = settings.length();
+        for (int i = 0; i < length; i++) {
+            final char c = settings.charAt(i);
+            if (Character.isWhitespace(c)) {
+                continue;
+            }
+            if (!(c == '\'' || c == '"') || length < i + 6 || settings.charAt(i + 5) != c) {
+                throw new InvalidFormatException(
+                        "Tag should be wrapped with double or single quote: " + settings);
+            }
+            final String tagString = settings.substring(i + 1, i + 5);
+
+            i += 6;  // Move to end of tag.
+            int endOfValueString = settings.indexOf(',', i);
+            if (endOfValueString == -1) {
+                endOfValueString = length;
+            }
+            final float value;
+            try {
+                // Float.parseFloat ignores leading/trailing whitespaces.
+                value = Float.parseFloat(settings.substring(i, endOfValueString));
+            } catch (NumberFormatException e) {
+                throw new InvalidFormatException("Failed to parse float string: " + e.getMessage());
+            }
+            axisList.add(new FontVariationAxis(tagString, value));
+            i = endOfValueString;
+        }
+        if (axisList.isEmpty()) {
+            return null;
+        }
+        return axisList.toArray(new FontVariationAxis[0]);
+    }
+
+    /**
+     * Stringify the array of FontVariationAxis.
+     *
+     * @param axes an array of FontVariationAxis.
+     * @return String a valid font variation settings string.
+     */
+    public static @NonNull String toFontVariationSettings(@Nullable FontVariationAxis[] axes) {
+        if (axes == null || axes.length == 0) {
+            return "";
+        }
+        return TextUtils.join(",", axes);
+    }
+}
+
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index dceb285..d4d0c99 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -189,9 +189,9 @@
         float amount, uint8_t*& dst) const {
     float oppAmount = 1.0f - amount;
     float a = start.a * oppAmount + end.a * amount;
-    *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f);
-    *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f);
-    *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f);
     *dst++ = uint8_t(a * 255.0f);
 }
 
@@ -202,13 +202,13 @@
     float* d = (float*) dst;
 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
     // We want to stay linear
-    *d++ = a * (start.r * oppAmount + end.r * amount);
-    *d++ = a * (start.g * oppAmount + end.g * amount);
-    *d++ = a * (start.b * oppAmount + end.b * amount);
+    *d++ = (start.r * oppAmount + end.r * amount);
+    *d++ = (start.g * oppAmount + end.g * amount);
+    *d++ = (start.b * oppAmount + end.b * amount);
 #else
-    *d++ = a * OECF(start.r * oppAmount + end.r * amount);
-    *d++ = a * OECF(start.g * oppAmount + end.g * amount);
-    *d++ = a * OECF(start.b * oppAmount + end.b * amount);
+    *d++ = OECF(start.r * oppAmount + end.r * amount);
+    *d++ = OECF(start.g * oppAmount + end.g * amount);
+    *d++ = OECF(start.b * oppAmount + end.b * amount);
 #endif
     *d++ = a;
     dst += 4 * sizeof(float);
@@ -229,10 +229,10 @@
     ChannelMixer mix = gMixers[mUseFloatTexture];
 
     FloatColor start;
-    start.setUnPreMultiplied(colors[0]);
+    start.set(colors[0]);
 
     FloatColor end;
-    end.setUnPreMultiplied(colors[1]);
+    end.set(colors[1]);
 
     int currentPos = 1;
     float startPos = positions[0];
@@ -247,7 +247,7 @@
 
             currentPos++;
 
-            end.setUnPreMultiplied(colors[currentPos]);
+            end.set(colors[currentPos]);
             distance = positions[currentPos] - startPos;
         }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 1f78e09..d0f0949 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -295,10 +295,6 @@
         vec4 dither(const vec4 color) {
             return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
         }
-        vec4 gradientMix(const vec4 a, const vec4 b, float v) {
-            vec4 c = mix(a, b, v);
-            return vec4(c.rgb * c.a, c.a);
-        }
         )__SHADER__",
         // sRGB framebuffer
         R"__SHADER__(
@@ -306,10 +302,6 @@
             vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
             return vec4(dithered * dithered, color.a);
         }
-        vec4 gradientMixMix(const vec4 a, const vec4 b, float v) {
-            vec4 c = mix(a, b, v);
-            return vec4(c.rgb * c.a, c.a);
-        }
         )__SHADER__",
 };
 
@@ -364,19 +356,19 @@
         // Linear
         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
 
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
 
         // Circular
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
 
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
 
         // Sweep
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
 
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
         "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 8a504d4..5c5378b 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,8 +173,8 @@
         outData->gradientSampler = 0;
         outData->gradientTexture = nullptr;
 
-        outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]);
-        outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]);
+        outData->startColor.set(gradInfo.fColors[0]);
+        outData->endColor.set(gradInfo.fColors[1]);
     }
 
     return true;
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index 7f06421..8826cfc 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -27,5 +27,7 @@
     libft2 \
     libminikin \
     libandroidfw \
-    libRScpp \
+    libRScpp
+
+LOCAL_STATIC_LIBRARIES += \
     libplatformprotos
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/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/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index fc60571..0b27d18 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;
@@ -567,9 +568,10 @@
     }
 
     /**
-     * Common base for the tables of TV programs.
+     * Common columns for the tables of TV programs.
+     * @hide
      */
-    public interface BaseProgramColumns extends BaseTvColumns {
+    interface ProgramColumns {
         /**
          * The title of this TV program.
          *
@@ -835,12 +837,13 @@
     }
 
     /**
-     * Common base for the tables of preview programs.
+     * Common columns for the tables of preview programs.
+     * @hide
      */
-    public interface BasePreviewProgramColumns extends BaseProgramColumns {
+    interface PreviewProgramColumns {
 
         /** @hide */
-        @StringDef({
+        @IntDef({
                 TYPE_MOVIE,
                 TYPE_TV_SERIES,
                 TYPE_TV_SEASON,
@@ -862,87 +865,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 +960,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 +968,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 +976,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 +984,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 +1000,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 +1015,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 +1093,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 +1129,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 +1142,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 +1155,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 +1188,7 @@
          * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
          * {@link #AVAILABILITY_PAID_CONTENT}.
          *
-         * <p>Type: TEXT
+         * <p>Type: INTEGER
          */
         String COLUMN_AVAILABILITY = "availability";
 
@@ -1327,15 +1327,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";
@@ -1363,7 +1363,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";
@@ -2229,7 +2229,7 @@
      * <p>By default, the query results will be sorted by
      * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} in ascending order.
      */
-    public static final class Programs implements BaseProgramColumns {
+    public static final class Programs implements BaseTvColumns, ProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2543,7 +2543,7 @@
      * <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
      * ascending order.
      */
-    public static final class RecordedPrograms implements BaseProgramColumns {
+    public static final class RecordedPrograms implements BaseTvColumns, ProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2665,7 +2665,8 @@
     /**
      * Column definitions for the preview TV programs table.
      */
-    public static final class PreviewPrograms implements BasePreviewProgramColumns {
+    public static final class PreviewPrograms implements BaseTvColumns, ProgramColumns,
+        PreviewProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2711,7 +2712,8 @@
     /**
      * Column definitions for the "watch next" TV programs table.
      */
-    public static final class WatchNextPrograms implements BasePreviewProgramColumns {
+    public static final class WatchNextPrograms implements BaseTvColumns, ProgramColumns,
+        PreviewProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2724,7 +2726,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,
@@ -2739,7 +2741,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
@@ -2749,7 +2751,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
@@ -2759,7 +2761,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
@@ -2768,7 +2770,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.
@@ -2781,7 +2783,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/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/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index c2ce7c9..8833fb8c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1394,7 +1394,9 @@
 
         @Override
         public boolean filterApp(AppEntry entry) {
-            if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+            if (AppUtils.isInstant(entry.info)) {
+                return false;
+            } else if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                 return true;
             } else if ((entry.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                 return true;
@@ -1407,6 +1409,23 @@
         }
     };
 
+    /**
+     * Displays a combined list with "downloaded" and "visible in launcher" apps only.
+     */
+    public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT = new AppFilter() {
+
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public boolean filterApp(AppEntry entry) {
+            return AppUtils.isInstant(entry.info)
+                    || FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry);
+        }
+
+    };
+
     public static final AppFilter FILTER_THIRD_PARTY = new AppFilter() {
         @Override
         public void init() {
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/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
index e204a3a..6a029f0 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
@@ -110,6 +110,70 @@
     }
 
     @Test
+    public void testDownloadAndLauncherAndInstantAcceptsCorrectApps() {
+        // should include instant apps
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = false;
+        when(mEntry.info.isInstantApp()).thenReturn(true);
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
+                .isTrue();
+
+        // should included updated system apps
+        when(mEntry.info.isInstantApp()).thenReturn(false);
+        mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
+                .isTrue();
+
+        // should not include system apps other than the home app
+        mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM;
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = false;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
+                .isFalse();
+
+        // should include the home app
+        mEntry.isHomeApp = true;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
+                .isTrue();
+
+        // should include any System app with a launcher entry
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = true;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry))
+                .isTrue();
+    }
+
+    @Test
+    public void testDownloadAndLauncherAcceptsCorrectApps() {
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = false;
+
+        // should included updated system apps
+        when(mEntry.info.isInstantApp()).thenReturn(false);
+        mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
+                .isTrue();
+
+        // should not include system apps other than the home app
+        mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM;
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = false;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
+                .isFalse();
+
+        // should include the home app
+        mEntry.isHomeApp = true;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
+                .isTrue();
+
+        // should include any System app with a launcher entry
+        mEntry.isHomeApp = false;
+        mEntry.hasLauncherEntry = true;
+        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry))
+                .isTrue();
+    }
+
+    @Test
     public void testInstantFilterAcceptsInstantApp() {
         when(mEntry.info.isInstantApp()).thenReturn(true);
         assertThat(ApplicationsState.FILTER_INSTANT.filterApp(mEntry)).isTrue();
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/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 4b2c20f..5b9d95d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2014 The Android Open Source Project
  *
@@ -358,9 +359,8 @@
         @Override
         public void onClick(View widget) {
             final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             mDialog.dismiss();
-            mContext.startActivity(intent);
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
         }
 
         @Override
@@ -373,9 +373,8 @@
         @Override
         public void onClick(View widget) {
             final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             mDialog.dismiss();
-            mContext.startActivity(intent);
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
         }
     }
 }
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/preloaded-classes b/preloaded-classes
index a72a042..892c593 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1817,7 +1817,6 @@
 android.text.FontConfig$Family$1
 android.text.FontConfig$Font
 android.text.FontConfig$Font$1
-android.text.FontManager
 android.text.GetChars
 android.text.GraphicsOperations
 android.text.Html
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/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 0e752ff..25ac008 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;
@@ -104,7 +97,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;
@@ -130,6 +122,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;
@@ -147,6 +140,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;
 
@@ -221,18 +215,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
@@ -246,6 +228,7 @@
     private INetworkManagementService mNetd;
     private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
+    private NetworkPolicyManagerInternal mPolicyManagerInternal;
 
     private String mCurrentTcpBufferSizes;
 
@@ -715,12 +698,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);
@@ -991,51 +977,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) {
@@ -1481,67 +1438,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 + ")");
-            }
         }
     };
 
@@ -1976,33 +1890,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()) {
@@ -3437,6 +3324,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);
@@ -4197,20 +4088,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/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
deleted file mode 100644
index f172647..0000000
--- a/services/core/java/com/android/server/FontManagerService.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.graphics.FontListParser;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.text.FontConfig;
-import android.util.Slog;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.font.IFontManager;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-public class FontManagerService extends IFontManager.Stub {
-    private static final String TAG = "FontManagerService";
-    private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
-    private static final String SYSTEM_FONT_DIR = "/system/fonts/";
-
-    @GuardedBy("mLock")
-    private FontConfig mConfig;
-    private final Object mLock = new Object();
-
-    public static final class Lifecycle extends SystemService {
-        private final FontManagerService mService;
-
-        public Lifecycle(Context context) {
-            super(context);
-            mService = new FontManagerService();
-        }
-
-        @Override
-        public void onStart() {
-            try {
-                publishBinderService(Context.FONT_SERVICE, mService);
-            } catch (Throwable t) {
-                // Starting this service is not critical to the running of this device and should
-                // therefore not crash the device. If it fails, log the error and continue.
-                Slog.e(TAG, "Could not start the FontManagerService.", t);
-            }
-        }
-    }
-
-    @Override
-    public FontConfig getSystemFonts() {
-        synchronized (mLock) {
-            if (mConfig != null) {
-                return mConfig;
-            }
-
-            mConfig = loadFromSystem();
-            if (mConfig == null) {
-                return null;
-            }
-
-            for (FontConfig.Family family : mConfig.getFamilies()) {
-                for (FontConfig.Font font : family.getFonts()) {
-                    File fontFile = new File(SYSTEM_FONT_DIR, font.getFontName());
-                    font.setUri(Uri.fromFile(fontFile));
-                }
-            }
-
-            return mConfig;
-        }
-    }
-
-    private FontConfig loadFromSystem() {
-        File configFilename = new File(FONTS_CONFIG);
-        try {
-            FileInputStream fontsIn = new FileInputStream(configFilename);
-            return FontListParser.parse(fontsIn);
-        } catch (IOException | XmlPullParserException e) {
-            Slog.e(TAG, "Error opening " + configFilename, e);
-        }
-        return null;
-    }
-
-    public FontManagerService() {
-    }
-}
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/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4ea49b..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;
@@ -17989,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,
@@ -18008,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,
@@ -18026,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;
     }
@@ -18268,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.
@@ -18329,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
@@ -18546,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)) {
@@ -18730,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
@@ -18774,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:
@@ -19154,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(
@@ -19396,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 "
@@ -19852,7 +19879,7 @@
 
     private void enforceWriteSettingsPermission(String func) {
         int uid = Binder.getCallingUid();
-        if (uid == Process.ROOT_UID) {
+        if (uid == ROOT_UID) {
             return;
         }
 
@@ -20050,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);
@@ -20061,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);
         }
 
@@ -20561,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;
                         }
@@ -21534,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
@@ -21562,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
                                     }
@@ -21587,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
                                     }
@@ -21602,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);
                             }
                         }
                     }
@@ -22728,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");
         }
 
@@ -22742,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);
                 }
             }
         }
@@ -23883,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 18e74080..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/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/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 5bdef9e..3705946 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -325,13 +325,11 @@
             // Disable all other overlays.
             allOverlays.remove(oi);
             for (int i = 0; i < allOverlays.size(); i++) {
-                mSettings.setEnabled(allOverlays.get(i).packageName, userId, false);
+                // TODO: Optimize this to only send updates after all changes.
+                setEnabled(allOverlays.get(i).packageName, false, userId);
             }
 
-            final PackageInfo targetPackage =
-                    mPackageManager.getPackageInfo(oi.targetPackageName, userId);
-            mSettings.setEnabled(packageName, userId, enable);
-            updateState(targetPackage, overlayPackage, userId);
+            setEnabled(packageName, enable, userId);
             return true;
         } catch (OverlayManagerSettings.BadKeyException e) {
             return false;
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 365a8e8..578b10a 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) {
@@ -16961,6 +16950,15 @@
                 return;
             }
 
+            // Shared libraries for the package need to be updated.
+            synchronized (mPackages) {
+                try {
+                    updateSharedLibrariesLPr(pkg, null);
+                } catch (PackageManagerException e) {
+                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+                }
+            }
+
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
             // Do not run PackageDexOptimizer through the local performDexOpt
             // method because `pkg` may not be in `mPackages` yet.
@@ -17009,6 +17007,7 @@
                         args.user, installerPackageName, volumeUuid, res, args.installReason);
             }
         }
+
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
             if (ps != 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/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 e73d4d25..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/core/java/com/android/internal/font/IFontManager.aidl b/services/core/java/com/android/server/wm/WindowHashMap.java
similarity index 65%
copy from core/java/com/android/internal/font/IFontManager.aidl
copy to services/core/java/com/android/server/wm/WindowHashMap.java
index 52a6262..49bba41 100644
--- a/core/java/com/android/internal/font/IFontManager.aidl
+++ b/services/core/java/com/android/server/wm/WindowHashMap.java
@@ -11,17 +11,18 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.internal.font;
+package com.android.server.wm;
 
-import android.text.FontConfig;
+import android.os.IBinder;
+
+import java.util.HashMap;
 
 /**
- * Interface to the font manager.
- * @hide
+ * Subclass of HashMap such that we can instruct the compiler to boost our thread priority when
+ * locking this class. See makefile.
  */
-interface IFontManager {
-    FontConfig getSystemFonts();
+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/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6fd95a4..8098eea 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2395,6 +2395,9 @@
         if (requestAnim) {
             mService.scheduleAnimationLocked();
         }
+        if ((mAttrs.flags & FLAG_NOT_FOCUSABLE) == 0) {
+            mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateImWindows */);
+        }
         return true;
     }
 
@@ -2437,6 +2440,9 @@
         if (requestAnim) {
             mService.scheduleAnimationLocked();
         }
+        if (mService.mCurrentFocus == this) {
+            mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateImWindows */);
+        }
         return true;
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index da49eb3..a5eac46 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);
     }
 
     /**
@@ -1014,12 +1017,6 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartFontServiceManager");
-                mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
-                traceEnd();
-            }
-
             if (!disableNonCoreServices && !disableTextServices) {
                 traceBeginAndSlog("StartTextServicesManager");
                 mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
diff --git a/services/profile-classes b/services/profile-classes
index 1b304e1..b0d2da7 100644
--- a/services/profile-classes
+++ b/services/profile-classes
@@ -2481,7 +2481,6 @@
 Landroid/text/FontConfig$Family$1;
 Landroid/text/FontConfig$Font;
 Landroid/text/FontConfig$Font$1;
-Landroid/text/FontManager;
 Landroid/text/format/DateFormat;
 Landroid/text/format/Time;
 Landroid/text/format/Time$TimeCalculator;
@@ -3132,8 +3131,6 @@
 Lcom/android/internal/content/PackageMonitor;
 Lcom/android/internal/content/ReferrerIntent;
 Lcom/android/internal/content/ReferrerIntent$1;
-Lcom/android/internal/font/IFontManager;
-Lcom/android/internal/font/IFontManager$Stub;
 Lcom/android/internal/graphics/drawable/AnimationScaleListDrawable;
 Lcom/android/internal/graphics/drawable/AnimationScaleListDrawable$AnimationScaleListState;
 Lcom/android/internal/hardware/AmbientDisplayConfiguration;
@@ -4377,8 +4374,6 @@
 Lcom/android/server/firewall/StringFilter$8;
 Lcom/android/server/firewall/StringFilter$9;
 Lcom/android/server/firewall/StringFilter$ValueProvider;
-Lcom/android/server/FontManagerService;
-Lcom/android/server/FontManagerService$Lifecycle;
 Lcom/android/server/GestureLauncherService;
 Lcom/android/server/GestureLauncherService$1;
 Lcom/android/server/GestureLauncherService$2;
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/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/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 04443a5..c562cb9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -80,6 +80,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 java.net.InetAddress;
 import java.util.ArrayList;
@@ -713,6 +714,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/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 7f71589..a33fd06 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -1913,7 +1913,7 @@
   std::vector<std::string> overlay_arg_list;
   std::vector<std::string> extra_java_packages;
   Maybe<std::string> package_id;
-  Maybe<std::string> configs;
+  std::vector<std::string> configs;
   Maybe<std::string> preferred_density;
   Maybe<std::string> product_list;
   bool legacy_x_flag = false;
@@ -1971,7 +1971,7 @@
                           &legacy_x_flag)
           .OptionalSwitch("-z", "Require localization of strings marked 'suggested'",
                           &require_localization)
-          .OptionalFlag("-c",
+          .OptionalFlagList("-c",
                         "Comma separated list of configurations to include. The default\n"
                         "is all configurations",
                         &configs)
@@ -2151,28 +2151,29 @@
   }
 
   AxisConfigFilter filter;
-  if (configs) {
-    for (const StringPiece& config_str : util::Tokenize(configs.value(), ',')) {
-      ConfigDescription config;
-      LocaleValue lv;
-      if (lv.InitFromFilterString(config_str)) {
-        lv.WriteTo(&config);
-      } else if (!ConfigDescription::Parse(config_str, &config)) {
-        context.GetDiagnostics()->Error(DiagMessage() << "invalid config '"
-                                                      << config_str
-                                                      << "' for -c option");
-        return 1;
-      }
+  if (configs.empty()) {
+    for (const std::string& config_arg : configs) {
+      for (const StringPiece& config_str : util::Tokenize(config_arg, ',')) {
+        ConfigDescription config;
+        LocaleValue lv;
+        if (lv.InitFromFilterString(config_str)) {
+          lv.WriteTo(&config);
+        } else if (!ConfigDescription::Parse(config_str, &config)) {
+          context.GetDiagnostics()->Error(DiagMessage() << "invalid config '"
+                                                        << config_str
+                                                        << "' for -c option");
+          return 1;
+        }
 
-      if (config.density != 0) {
-        context.GetDiagnostics()->Warn(DiagMessage() << "ignoring density '"
-                                                     << config
-                                                     << "' for -c option");
-      } else {
-        filter.AddConfig(config);
+        if (config.density != 0) {
+          context.GetDiagnostics()->Warn(DiagMessage() << "ignoring density '"
+                                                       << config
+                                                       << "' for -c option");
+        } else {
+          filter.AddConfig(config);
+        }
       }
     }
-
     options.table_splitter_options.config_filter = &filter;
   }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 7fe464a..a21fe68 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -26,6 +26,7 @@
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.content.res.BridgeAssetManager;
+import android.graphics.fonts.FontVariationAxis;
 import android.text.FontConfig;
 
 import java.awt.Font;
@@ -250,7 +251,7 @@
     // ---- delegate methods ----
     @LayoutlibDelegate
     /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex,
-            FontConfig.Axis[] axes, int weight, int italic) {
+            FontVariationAxis[] axes, int weight, int italic) {
         if (thisFontFamily.mBuilderPtr == 0) {
             assert false : "Unable to call addFont after freezing.";
             return false;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 80e3bad..c7818a3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -23,6 +23,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.FontFamily_Delegate.FontVariant;
+import android.graphics.fonts.FontVariationAxis;
 import android.text.FontConfig;
 
 import java.awt.Font;
@@ -163,7 +164,7 @@
 
     @LayoutlibDelegate
     /*package*/ static synchronized long nativeCreateFromTypefaceWithVariation(long native_instance,
-            List<FontConfig.Axis> axes) {
+            List<FontVariationAxis> axes) {
         long newInstance = nativeCreateFromTypeface(native_instance, 0);
 
         if (newInstance != 0) {