Merge "Move Session2Command result codes into Result class"
diff --git a/Android.bp b/Android.bp
index 035420f..4c07fcf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -248,7 +248,6 @@
         "core/java/android/os/ICancellationSignal.aidl",
         "core/java/android/os/IDeviceIdentifiersPolicyService.aidl",
         "core/java/android/os/IDeviceIdleController.aidl",
-        "core/java/android/os/IDynamicAndroidService.aidl",
         "core/java/android/os/IHardwarePropertiesManager.aidl",
         ":libincident_aidl",
         "core/java/android/os/IMaintenanceActivityListener.aidl",
@@ -272,6 +271,7 @@
         "core/java/android/os/IUserManager.aidl",
         ":libvibrator_aidl",
         "core/java/android/os/IVibratorService.aidl",
+        "core/java/android/os/image/IDynamicSystemService.aidl",
         "core/java/android/os/storage/IStorageManager.aidl",
         "core/java/android/os/storage/IStorageEventListener.aidl",
         "core/java/android/os/storage/IStorageShutdownObserver.aidl",
@@ -886,66 +886,6 @@
     output_extension: "srcjar",
 }
 
-// AIDL interfaces between the core system and the networking mainline module.
-aidl_interface {
-    name: "networkstack-aidl-interfaces",
-    local_include_dir: "core/java",
-    srcs: [
-        "core/java/android/net/ApfCapabilitiesParcelable.aidl",
-        "core/java/android/net/DhcpResultsParcelable.aidl",
-        "core/java/android/net/INetworkMonitor.aidl",
-        "core/java/android/net/INetworkMonitorCallbacks.aidl",
-        "core/java/android/net/INetworkStackConnector.aidl",
-        "core/java/android/net/INetworkStackStatusCallback.aidl",
-        "core/java/android/net/InitialConfigurationParcelable.aidl",
-        "core/java/android/net/PrivateDnsConfigParcel.aidl",
-        "core/java/android/net/ProvisioningConfigurationParcelable.aidl",
-        "core/java/android/net/StaticIpConfigurationParcelable.aidl",
-        "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
-        "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
-        "core/java/android/net/dhcp/IDhcpServer.aidl",
-        "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
-        "core/java/android/net/ip/IIpClient.aidl",
-        "core/java/android/net/ip/IIpClientCallbacks.aidl",
-        "core/java/android/net/IIpMemoryStore.aidl",
-        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
-        "core/java/android/net/ipmemorystore/**/*.aidl",
-    ],
-    backend: {
-        ndk: {
-            enabled: false,
-        },
-        cpp: {
-            enabled: false,
-        },
-    },
-    api_dir: "aidl/networkstack",
-}
-
-aidl_interface {
-    name: "ipmemorystore-aidl-interfaces",
-    local_include_dir: "core/java",
-    srcs: [
-        "core/java/android/net/IIpMemoryStore.aidl",
-        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
-        "core/java/android/net/ipmemorystore/**/*.aidl",
-    ],
-}
-
-aidl_interface {
-    name: "networkstack-aidl-framework",
-    local_include_dir: "core/java",
-    srcs: [
-        "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
-    ],
-    api_dir: "aidl/networkstack",
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-    },
-}
-
 filegroup {
     name: "framework-annotations",
     srcs: [
diff --git a/api/current.txt b/api/current.txt
index a94e469..e03bc61 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5481,10 +5481,10 @@
     method public boolean getAutoExpandBubble();
     method @Nullable public android.app.PendingIntent getDeleteIntent();
     method public int getDesiredHeight();
+    method @DimenRes public int getDesiredHeightResId();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public android.app.PendingIntent getIntent();
     method public boolean getSuppressInitialNotification();
-    method @Deprecated public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
   }
@@ -5495,10 +5495,10 @@
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(@Nullable android.app.PendingIntent);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
-    method @Deprecated public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
   }
 
   public static class Notification.Builder {
@@ -5848,8 +5848,8 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
-    field public static final String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
-    field public static final String META_DATA_RULE_INSTANCE_LIMIT = "android.app.zen.automatic.ruleInstanceLimit";
+    field public static final String META_DATA_AUTOMATIC_RULE_TYPE = "android.service.zen.automatic.ruleType";
+    field public static final String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
@@ -9794,6 +9794,7 @@
     field public static final int BIND_DEBUG_UNBIND = 2; // 0x2
     field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000
     field public static final int BIND_IMPORTANT = 64; // 0x40
+    field public static final int BIND_INCLUDE_CAPABILITIES = 4096; // 0x1000
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
     field public static final String BIOMETRIC_SERVICE = "biometric";
@@ -12356,6 +12357,7 @@
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException;
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int);
+    method public void rebase();
     method public boolean resolveAttribute(int, android.util.TypedValue, boolean);
     method public void setTo(android.content.res.Resources.Theme);
   }
@@ -22664,18 +22666,22 @@
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
     method public double getBiasNanos();
-    method public double getBiasUncertaintyNanos();
+    method @FloatRange(from=0.0f) public double getBiasUncertaintyNanos();
     method public double getDriftNanosPerSecond();
-    method public double getDriftUncertaintyNanosPerSecond();
+    method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
+    method public long getElapsedRealtimeNanos();
+    method @IntRange(from=0) public long getElapsedRealtimeUncertaintyNanos();
     method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
     method public int getLeapSecond();
     method public long getTimeNanos();
-    method public double getTimeUncertaintyNanos();
+    method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
     method public boolean hasBiasNanos();
     method public boolean hasBiasUncertaintyNanos();
     method public boolean hasDriftNanosPerSecond();
     method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasElapsedRealtimeNanos();
+    method public boolean hasElapsedRealtimeUncertaintyNanos();
     method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
     method public boolean hasTimeUncertaintyNanos();
@@ -23249,7 +23255,7 @@
     method public static boolean isHapticPlaybackSupported();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
-    method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat);
+    method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
@@ -23484,11 +23490,11 @@
     method public void release();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method @Deprecated public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
-    method public boolean setMicrophoneDirection(int);
-    method public boolean setMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
+    method public boolean setPreferredMicrophoneDirection(int);
+    method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
     method public void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener);
     method public void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener, android.os.Handler);
     method public void startRecording() throws java.lang.IllegalStateException;
@@ -23760,12 +23766,6 @@
     field public static final int QUALITY_MEDIUM = 1; // 0x1
   }
 
-  public abstract class DataSourceCallback implements java.io.Closeable {
-    ctor public DataSourceCallback();
-    method public abstract long getSize() throws java.io.IOException;
-    method public abstract int readAt(long, @NonNull byte[], int, int) throws java.io.IOException;
-  }
-
   public class DataSourceDesc {
     method public long getEndPosition();
     method @Nullable public String getMediaId();
@@ -23782,7 +23782,6 @@
     method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
     method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
     method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
-    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
     method @NonNull public android.media.DataSourceDesc.Builder setEndPosition(long);
     method @NonNull public android.media.DataSourceDesc.Builder setMediaId(@Nullable String);
     method @NonNull public android.media.DataSourceDesc.Builder setStartPosition(long);
@@ -24853,6 +24852,7 @@
     field public static final int STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
     field public static final int STATUS_PENDING = 3; // 0x3
     field public static final int STATUS_USABLE = 0; // 0x0
+    field public static final int STATUS_USABLE_IN_FUTURE = 5; // 0x5
   }
 
   public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
@@ -24925,6 +24925,7 @@
     ctor public MediaDrm.SessionException(int, @Nullable String);
     method public int getErrorCode();
     field public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
   }
 
   public class MediaDrmException extends java.lang.Exception {
@@ -25553,8 +25554,8 @@
     method @NonNull public Object clearNextDataSources();
     method public void clearPendingCommands();
     method public void close();
-    method @NonNull public Object deselectTrack(int);
-    method @NonNull public Object deselectTrack(@NonNull android.media.DataSourceDesc, int);
+    method @NonNull public Object deselectTrack(@NonNull android.media.MediaPlayer2.TrackInfo);
+    method @NonNull public Object deselectTrack(@NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.TrackInfo);
     method @NonNull public android.media.AudioAttributes getAudioAttributes();
     method public int getAudioSessionId();
     method public long getBufferedPosition();
@@ -25569,8 +25570,8 @@
     method public float getPlayerVolume();
     method @Nullable public android.media.AudioDeviceInfo getPreferredDevice();
     method @Nullable public android.media.AudioDeviceInfo getRoutedDevice();
-    method public int getSelectedTrack(int);
-    method public int getSelectedTrack(@NonNull android.media.DataSourceDesc, int);
+    method @Nullable public android.media.MediaPlayer2.TrackInfo getSelectedTrack(int);
+    method @Nullable public android.media.MediaPlayer2.TrackInfo getSelectedTrack(@NonNull android.media.DataSourceDesc, int);
     method public int getState();
     method @NonNull public android.media.SyncParams getSyncParams();
     method @Nullable public android.media.MediaTimestamp getTimestamp();
@@ -25588,8 +25589,8 @@
     method public void reset();
     method @NonNull public Object seekTo(long);
     method @NonNull public Object seekTo(long, int);
-    method @NonNull public Object selectTrack(int);
-    method @NonNull public Object selectTrack(@NonNull android.media.DataSourceDesc, int);
+    method @NonNull public Object selectTrack(@NonNull android.media.MediaPlayer2.TrackInfo);
+    method @NonNull public Object selectTrack(@NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.TrackInfo);
     method @NonNull public Object setAudioAttributes(@NonNull android.media.AudioAttributes);
     method @NonNull public Object setAudioSessionId(int);
     method @NonNull public Object setAuxEffectSendLevel(float);
@@ -25682,11 +25683,11 @@
     field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
   }
 
-  public static class MediaPlayer2.DrmEventCallback {
+  public abstract static class MediaPlayer2.DrmEventCallback {
     ctor public MediaPlayer2.DrmEventCallback();
     method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
-    method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
-    method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+    method @Nullable public abstract android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
+    method @NonNull public abstract byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
     method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
   }
 
@@ -25696,17 +25697,22 @@
   }
 
   public static final class MediaPlayer2.DrmPreparationInfo {
+    method @Nullable public byte[] getInitData();
+    method @Nullable public byte[] getKeySetId();
+    method public int getKeyType();
+    method @Nullable public String getMimeType();
+    method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOptionalParameters();
+    method @NonNull public java.util.UUID getUuid();
   }
 
   public static final class MediaPlayer2.DrmPreparationInfo.Builder {
-    ctor public MediaPlayer2.DrmPreparationInfo.Builder();
+    ctor public MediaPlayer2.DrmPreparationInfo.Builder(@NonNull java.util.UUID);
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build();
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
     method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
-    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
   }
 
   public static class MediaPlayer2.EventCallback {
@@ -25716,7 +25722,7 @@
     method public void onError(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int);
     method public void onInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int);
     method public void onMediaTimeDiscontinuity(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaTimestamp);
-    method public void onSubtitleData(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.SubtitleData);
+    method public void onSubtitleData(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.SubtitleData);
     method public void onTimedMetaDataAvailable(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.TimedMetaData);
     method public void onVideoSizeChanged(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.util.Size);
   }
@@ -25740,6 +25746,13 @@
     ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String);
   }
 
+  public static final class MediaPlayer2.SubtitleData {
+    method @NonNull public byte[] getData();
+    method public long getDurationUs();
+    method public long getStartTimeUs();
+    method @NonNull public android.media.MediaPlayer2.TrackInfo getTrackInfo();
+  }
+
   public static class MediaPlayer2.TrackInfo {
     method @Nullable public android.media.MediaFormat getFormat();
     method @NonNull public String getLanguage();
@@ -25781,8 +25794,6 @@
     method public void setLocation(float, float);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
-    method public boolean setMicrophoneDirection(int);
-    method public boolean setMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
     method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException;
     method public void setNextOutputFile(java.io.File) throws java.io.IOException;
     method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener);
@@ -25793,6 +25804,8 @@
     method public void setOutputFile(String) throws java.lang.IllegalStateException;
     method public void setOutputFormat(int) throws java.lang.IllegalStateException;
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
+    method public boolean setPreferredMicrophoneDirection(int);
+    method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
     method public void setPreviewDisplay(android.view.Surface);
     method public void setProfile(android.media.CamcorderProfile);
     method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
@@ -26136,11 +26149,11 @@
   }
 
   public interface MicrophoneDirection {
-    method public boolean setMicrophoneDirection(int);
-    method public boolean setMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
-    field public static final int MIC_DIRECTION_BACK = 2; // 0x2
+    method public boolean setPreferredMicrophoneDirection(int);
+    method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
+    field public static final int MIC_DIRECTION_AWAY_FROM_USER = 2; // 0x2
     field public static final int MIC_DIRECTION_EXTERNAL = 3; // 0x3
-    field public static final int MIC_DIRECTION_FRONT = 1; // 0x1
+    field public static final int MIC_DIRECTION_TOWARDS_USER = 1; // 0x1
     field public static final int MIC_DIRECTION_UNSPECIFIED = 0; // 0x0
   }
 
@@ -28733,8 +28746,8 @@
 
   public final class DnsResolver {
     method @NonNull public static android.net.DnsResolver getInstance();
-    method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
-    method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+    method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+    method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
     field public static final int CLASS_IN = 1; // 0x1
     field public static final int FLAG_EMPTY = 0; // 0x0
     field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -30746,7 +30759,6 @@
     method public double getAltitudeUncertainty();
     method public java.util.List<android.net.MacAddress> getColocatedBssids();
     method public int getDatum();
-    method public boolean getDependentStationIndication();
     method public int getExpectedToMove();
     method public double getFloorNumber();
     method public double getHeightAboveFloorMeters();
@@ -30759,7 +30771,6 @@
     method @Nullable public String getMapImageMimeType();
     method @Nullable public android.net.Uri getMapImageUri();
     method public boolean getRegisteredLocationAgreementIndication();
-    method public boolean getRegisteredLocationDseIndication();
     method public boolean isLciSubelementValid();
     method public boolean isZaxisSubelementValid();
     method @Nullable public android.location.Address toCivicLocationAddress();
@@ -34603,6 +34614,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.DropBoxManager.Entry getNextEntry(String, long);
     method public boolean isTagEnabled(String);
     field public static final String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
+    field public static final String EXTRA_DROPPED_COUNT = "android.os.extra.DROPPED_COUNT";
     field public static final String EXTRA_TAG = "tag";
     field public static final String EXTRA_TIME = "time";
     field public static final int IS_EMPTY = 1; // 0x1
@@ -38749,8 +38761,7 @@
     field public static final String MIME_TYPE = "mime_type";
     field public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
     field public static final String OWNER_PACKAGE_NAME = "owner_package_name";
-    field public static final String PRIMARY_DIRECTORY = "primary_directory";
-    field public static final String SECONDARY_DIRECTORY = "secondary_directory";
+    field public static final String RELATIVE_PATH = "relative_path";
     field public static final String SIZE = "_size";
     field public static final String TITLE = "title";
     field public static final String WIDTH = "width";
@@ -45019,7 +45030,7 @@
     method public String getCountryIso();
     method public int getDataRoaming();
     method public CharSequence getDisplayName();
-    method @Nullable public String getGroupUuid();
+    method @Nullable public android.os.ParcelUuid getGroupUuid();
     method public String getIccId();
     method public int getIconTint();
     method @Deprecated public int getMcc();
@@ -45039,7 +45050,9 @@
   public class SubscriptionManager {
     method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
     method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
     method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
     method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
@@ -45055,16 +45068,15 @@
     method public static int getSlotIndex(int);
     method @Nullable public int[] getSubscriptionIds(int);
     method @NonNull public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(@NonNull android.os.ParcelUuid);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isActiveSubscriptionId(int);
     method public boolean isNetworkRoaming(int);
     method public static boolean isUsableSubscriptionId(int);
     method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
-    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, long);
     method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
diff --git a/api/removed.txt b/api/removed.txt
index fa07094..fe3e866 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -524,6 +524,8 @@
   public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
     field @Deprecated public static final String HASH = "_hash";
     field @Deprecated public static final String IS_TRASHED = "is_trashed";
+    field @Deprecated public static final String PRIMARY_DIRECTORY = "primary_directory";
+    field @Deprecated public static final String SECONDARY_DIRECTORY = "secondary_directory";
   }
 
   @Deprecated public static class MediaStore.PendingParams {
diff --git a/api/system-current.txt b/api/system-current.txt
index dd5c9c9..876c2b2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12,6 +12,7 @@
     field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP";
     field public static final String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
     field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
+    field public static final String ACCESS_SHARED_LIBRARIES = "android.permission.ACCESS_SHARED_LIBRARIES";
     field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
     field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
@@ -117,6 +118,7 @@
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
+    field public static final String NETWORK_SCAN = "android.permission.NETWORK_SCAN";
     field public static final String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
     field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
     field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
@@ -186,7 +188,6 @@
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
     field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
-    field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -1063,7 +1064,7 @@
   public final class AppPredictor {
     method public void destroy();
     method public void notifyAppTargetEvent(@NonNull android.app.prediction.AppTargetEvent);
-    method public void notifyLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method public void notifyLaunchLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
     method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
     method public void requestPredictionUpdate();
     method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
@@ -1075,8 +1076,6 @@
   }
 
   public final class AppTarget implements android.os.Parcelable {
-    ctor public AppTarget(@NonNull android.app.prediction.AppTargetId, @NonNull String, @Nullable String, @NonNull android.os.UserHandle);
-    ctor public AppTarget(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo, @Nullable String);
     method public int describeContents();
     method @Nullable public String getClassName();
     method @NonNull public android.app.prediction.AppTargetId getId();
@@ -1088,6 +1087,15 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
   }
 
+  public static final class AppTarget.Builder {
+    ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId);
+    method @NonNull public android.app.prediction.AppTarget build();
+    method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String);
+    method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int);
+    method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle);
+    method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo);
+  }
+
   public final class AppTargetEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -1353,7 +1361,6 @@
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
-    field public static final String DYNAMIC_ANDROID_SERVICE = "dynamic_android";
     field public static final String EUICC_CARD_SERVICE = "euicc_card";
     field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final String NETD_SERVICE = "netd";
@@ -1380,32 +1387,6 @@
     method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
   }
 
-  public class DynamicAndroidClient {
-    ctor public DynamicAndroidClient(@NonNull android.content.Context);
-    method public void bind();
-    method public void setOnStatusChangedListener(@NonNull android.content.DynamicAndroidClient.OnStatusChangedListener, @NonNull java.util.concurrent.Executor);
-    method public void setOnStatusChangedListener(@NonNull android.content.DynamicAndroidClient.OnStatusChangedListener);
-    method public void start(String, long);
-    method public void start(String, long, long);
-    method public void unbind();
-    field public static final int CAUSE_ERROR_EXCEPTION = 6; // 0x6
-    field public static final int CAUSE_ERROR_INVALID_URL = 4; // 0x4
-    field public static final int CAUSE_ERROR_IO = 3; // 0x3
-    field public static final int CAUSE_ERROR_IPC = 5; // 0x5
-    field public static final int CAUSE_INSTALL_CANCELLED = 2; // 0x2
-    field public static final int CAUSE_INSTALL_COMPLETED = 1; // 0x1
-    field public static final int CAUSE_NOT_SPECIFIED = 0; // 0x0
-    field public static final int STATUS_IN_PROGRESS = 2; // 0x2
-    field public static final int STATUS_IN_USE = 4; // 0x4
-    field public static final int STATUS_NOT_STARTED = 1; // 0x1
-    field public static final int STATUS_READY = 3; // 0x3
-    field public static final int STATUS_UNKNOWN = 0; // 0x0
-  }
-
-  public static interface DynamicAndroidClient.OnStatusChangedListener {
-    method public void onStatusChanged(int, int, long);
-  }
-
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
     field public static final String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
     field public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
@@ -1429,7 +1410,6 @@
     field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
-    field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
     field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
@@ -1438,6 +1418,7 @@
     field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
     field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
     field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
+    field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
     field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
     field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
     field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
@@ -1480,15 +1461,16 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.om.OverlayInfo> CREATOR;
     field public final String category;
     field public final String packageName;
+    field public final String targetOverlayableName;
     field public final String targetPackageName;
     field public final int userId;
   }
 
   public class OverlayManager {
     method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle);
-    method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int);
-    method public boolean setEnabled(@Nullable String, boolean, int);
-    method public boolean setEnabledExclusiveInCategory(@Nullable String, int);
+    method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle);
   }
 
 }
@@ -1614,6 +1596,7 @@
     method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public android.content.pm.dex.ArtManager getArtManager();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_SHARED_LIBRARIES) public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
     method public String getIncidentReportApproverPackageName();
@@ -1844,9 +1827,9 @@
   }
 
   public final class RollbackManager {
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -3663,13 +3646,14 @@
 
   public static class AudioPolicy.Builder {
     ctor public AudioPolicy.Builder(android.content.Context);
-    method public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
-    method public android.media.audiopolicy.AudioPolicy build();
+    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
+    method @NonNull 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 setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback);
-    method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean);
-    method public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback);
+    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean);
+    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean);
+    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException;
   }
 
   public final class AudioProductStrategies implements java.lang.Iterable<android.media.audiopolicy.AudioProductStrategy> android.os.Parcelable {
@@ -4027,7 +4011,6 @@
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
-    ctor public CaptivePortal(@NonNull android.os.IBinder);
     method public void logEvent(int, @NonNull String);
     method public void useNetwork();
     field public static final int APP_RETURN_DISMISSED = 0; // 0x0
@@ -4038,12 +4021,12 @@
   public class ConnectivityManager {
     method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method public boolean getAvoidBadWifi();
     method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "android.permission.NETWORK_STACK"}) public boolean shouldAvoidBadWifi();
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
@@ -4929,7 +4912,6 @@
     method public int getCellularDataNetworkType();
     method public int getCellularSignalStrengthDb();
     method public int getCellularSignalStrengthDbm();
-    method public boolean getIsSameRegisteredCell();
     method public int getLinkSpeedMbps();
     method public int getProbeElapsedTimeSinceLastUpdateMillis();
     method public int getProbeMcsRateSinceLastUpdate();
@@ -4953,6 +4935,7 @@
     method public long getTotalTxBad();
     method public long getTotalTxRetries();
     method public long getTotalTxSuccess();
+    method public boolean isSameRegisteredCell();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR;
     field public static final int PROBE_STATUS_FAILURE = 3; // 0x3
@@ -5442,14 +5425,14 @@
   public final class PowerManager {
     method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
     method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
-    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveMode();
+    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger();
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
-    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSavings(boolean, int);
+    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
-    field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
-    field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
+    field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
+    field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -5656,6 +5639,36 @@
 
 }
 
+package android.os.image {
+
+  public class DynamicSystemClient {
+    ctor public DynamicSystemClient(@NonNull android.content.Context);
+    method @RequiresPermission("android.permission.MANAGE_DYNAMIC_SYSTEM") public void bind();
+    method public void setOnStatusChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
+    method public void setOnStatusChangedListener(@NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
+    method @RequiresPermission("android.permission.MANAGE_DYNAMIC_SYSTEM") public void start(@NonNull String, long);
+    method @RequiresPermission("android.permission.MANAGE_DYNAMIC_SYSTEM") public void start(@NonNull String, long, long);
+    method @RequiresPermission("android.permission.MANAGE_DYNAMIC_SYSTEM") public void unbind();
+    field public static final int CAUSE_ERROR_EXCEPTION = 6; // 0x6
+    field public static final int CAUSE_ERROR_INVALID_URL = 4; // 0x4
+    field public static final int CAUSE_ERROR_IO = 3; // 0x3
+    field public static final int CAUSE_ERROR_IPC = 5; // 0x5
+    field public static final int CAUSE_INSTALL_CANCELLED = 2; // 0x2
+    field public static final int CAUSE_INSTALL_COMPLETED = 1; // 0x1
+    field public static final int CAUSE_NOT_SPECIFIED = 0; // 0x0
+    field public static final int STATUS_IN_PROGRESS = 2; // 0x2
+    field public static final int STATUS_IN_USE = 4; // 0x4
+    field public static final int STATUS_NOT_STARTED = 1; // 0x1
+    field public static final int STATUS_READY = 3; // 0x3
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  public static interface DynamicSystemClient.OnStatusChangedListener {
+    method public void onStatusChanged(int, int, long);
+  }
+
+}
+
 package android.os.storage {
 
   public class StorageManager {
@@ -6035,6 +6048,7 @@
     field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
     field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
+    field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
     field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
     field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
   }
@@ -6292,7 +6306,7 @@
     method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
-    method @MainThread public abstract void onLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method @MainThread public abstract void onLaunchLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
     method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
     method @MainThread public void onStartPredictionUpdates();
@@ -6306,12 +6320,15 @@
 
   public abstract class AttentionService extends android.app.Service {
     ctor public AttentionService();
+    method public final void disableSelf();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onCancelAttentionCheck(int);
     method public abstract void onCheckAttention(int, @NonNull android.service.attention.AttentionService.AttentionCallback);
-    field public static final int ATTENTION_FAILURE_PREEMPTED = 2; // 0x2
-    field public static final int ATTENTION_FAILURE_TIMED_OUT = 3; // 0x3
-    field public static final int ATTENTION_FAILURE_UNKNOWN = 4; // 0x4
+    field public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6; // 0x6
+    field public static final int ATTENTION_FAILURE_CANCELLED = 3; // 0x3
+    field public static final int ATTENTION_FAILURE_PREEMPTED = 4; // 0x4
+    field public static final int ATTENTION_FAILURE_TIMED_OUT = 5; // 0x5
+    field public static final int ATTENTION_FAILURE_UNKNOWN = 2; // 0x2
     field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
     field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
     field public static final String SERVICE_INTERFACE = "android.service.attention.AttentionService";
@@ -6418,7 +6435,7 @@
 
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
-    method public final void disableContentCaptureServices();
+    method public final void disableSelf();
     method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent);
     method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
@@ -7558,11 +7575,11 @@
     field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
   }
 
-  public final class DataSpecificRegistrationStates implements android.os.Parcelable {
+  public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
     method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationStates> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
   }
 
   public final class DisconnectCause {
@@ -7671,7 +7688,7 @@
     method public int getAccessNetworkTechnology();
     method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
-    method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates();
+    method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
     method public int getDomain();
     method public int getRegistrationState();
     method public int getRejectCause();
@@ -9478,6 +9495,10 @@
     method public int getUid();
   }
 
+  public final class StatsLog {
+    method public static void writeRaw(@NonNull byte[], int);
+  }
+
   public class StatsLogAtoms {
     field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED = 170; // 0xaa
     field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED = 8; // 0x8
diff --git a/api/test-current.txt b/api/test-current.txt
index 417a9ed..6532cf8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -352,6 +352,10 @@
     method public boolean isUiModeLocked();
   }
 
+  public class WallpaperManager {
+    method @RequiresPermission("android.permission.SET_WALLPAPER_COMPONENT") public boolean setWallpaperComponent(android.content.ComponentName);
+  }
+
   public class WindowConfiguration implements java.lang.Comparable<android.app.WindowConfiguration> android.os.Parcelable {
     ctor public WindowConfiguration();
     method public int compareTo(android.app.WindowConfiguration);
@@ -461,7 +465,7 @@
     method public void destroy();
     method public android.app.prediction.AppPredictionSessionId getSessionId();
     method public void notifyAppTargetEvent(@NonNull android.app.prediction.AppTargetEvent);
-    method public void notifyLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method public void notifyLaunchLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
     method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
     method public void requestPredictionUpdate();
     method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
@@ -473,7 +477,6 @@
   }
 
   public final class AppTarget implements android.os.Parcelable {
-    ctor public AppTarget(@NonNull android.app.prediction.AppTargetId, @NonNull String, @Nullable String, @NonNull android.os.UserHandle);
     method public int describeContents();
     method @Nullable public String getClassName();
     method @NonNull public android.app.prediction.AppTargetId getId();
@@ -485,6 +488,15 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
   }
 
+  public static final class AppTarget.Builder {
+    ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId);
+    method @NonNull public android.app.prediction.AppTarget build();
+    method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String);
+    method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int);
+    method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle);
+    method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo);
+  }
+
   public final class AppTargetEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -576,12 +588,14 @@
   }
 
   public final class ContentCaptureOptions implements android.os.Parcelable {
+    ctor public ContentCaptureOptions(int);
     ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>);
     method public int describeContents();
     method public static android.content.ContentCaptureOptions forWhitelistingItself();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentCaptureOptions> CREATOR;
     field public final int idleFlushingFrequencyMs;
+    field public final boolean lite;
     field public final int logHistorySize;
     field public final int loggingLevel;
     field public final int maxBufferSize;
@@ -600,6 +614,7 @@
   public abstract class Context {
     method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.view.Display getDisplay();
+    method public abstract int getDisplayId();
     method public android.os.UserHandle getUser();
     method public int getUserId();
     method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
@@ -610,6 +625,7 @@
 
   public class ContextWrapper extends android.content.Context {
     method public android.view.Display getDisplay();
+    method public int getDisplayId();
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
@@ -919,19 +935,23 @@
     method public void resetBiasUncertaintyNanos();
     method public void resetDriftNanosPerSecond();
     method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetElapsedRealtimeNanos();
+    method public void resetElapsedRealtimeUncertaintyNanos();
     method public void resetFullBiasNanos();
     method public void resetLeapSecond();
     method public void resetTimeUncertaintyNanos();
     method public void set(android.location.GnssClock);
     method public void setBiasNanos(double);
-    method public void setBiasUncertaintyNanos(double);
+    method public void setBiasUncertaintyNanos(@FloatRange(from=0.0f) double);
     method public void setDriftNanosPerSecond(double);
-    method public void setDriftUncertaintyNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
+    method public void setElapsedRealtimeNanos(long);
+    method public void setElapsedRealtimeUncertaintyNanos(@IntRange(from=0) long);
     method public void setFullBiasNanos(long);
     method public void setHardwareClockDiscontinuityCount(int);
     method public void setLeapSecond(int);
     method public void setTimeNanos(long);
-    method public void setTimeUncertaintyNanos(double);
+    method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
   }
 
   public final class GnssMeasurement implements android.os.Parcelable {
@@ -1078,10 +1098,6 @@
     method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
   }
 
-  public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
-    method @NonNull public android.media.DataSourceCallback getDataSourceCallback();
-  }
-
   public class FileDataSourceDesc extends android.media.DataSourceDesc {
     method public long getLength();
     method public long getOffset();
@@ -1207,7 +1223,6 @@
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
-    ctor public CaptivePortal(@NonNull android.os.IBinder);
     method public void logEvent(int, @NonNull String);
     method public void useNetwork();
     field public static final int APP_RETURN_DISMISSED = 0; // 0x0
@@ -1796,11 +1811,11 @@
   }
 
   public final class PowerManager {
-    method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveMode();
-    method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSavings(boolean, int);
+    method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveModeTrigger();
+    method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSaveHint(boolean, int);
     method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean);
-    field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
-    field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
+    field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
+    field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
   }
 
   public class Process {
@@ -2148,7 +2163,7 @@
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
     field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
-    field public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+    field public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
     field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
     field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs";
     field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
@@ -2258,7 +2273,7 @@
     method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
-    method @MainThread public abstract void onLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method @MainThread public abstract void onLaunchLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
     method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
     method @MainThread public void onStartPredictionUpdates();
@@ -2433,7 +2448,7 @@
 
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
-    method public final void disableContentCaptureServices();
+    method public final void disableSelf();
     method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent);
     method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
@@ -2552,10 +2567,34 @@
 
 package android.telephony {
 
+  public final class AccessNetworkConstants {
+    field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
+    field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
+  }
+
   public class CarrierConfigManager {
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
   }
 
+  public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
+  }
+
+  public final class LteVopsSupportInfo implements android.os.Parcelable {
+    ctor public LteVopsSupportInfo(int, int);
+    method public int describeContents();
+    method public int getEmcBearerSupport();
+    method public int getVopsSupport();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
+    field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
+    field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
+    field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
+  }
+
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
     field public static final String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
   }
@@ -2568,12 +2607,59 @@
     field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
   }
 
+  public final class NetworkRegistrationInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAccessNetworkTechnology();
+    method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
+    method @Nullable public android.telephony.CellIdentity getCellIdentity();
+    method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
+    method public int getDomain();
+    method public int getRegistrationState();
+    method public int getRejectCause();
+    method public int getRoamingType();
+    method public int getTransportType();
+    method public boolean isEmergencyEnabled();
+    method public boolean isRoaming();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
+    field public static final int DOMAIN_CS = 1; // 0x1
+    field public static final int DOMAIN_PS = 2; // 0x2
+    field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
+    field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
+    field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
+    field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
+    field public static final int SERVICE_TYPE_DATA = 2; // 0x2
+    field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
+    field public static final int SERVICE_TYPE_SMS = 3; // 0x3
+    field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
+    field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
+  }
+
+  public static final class NetworkRegistrationInfo.Builder {
+    ctor public NetworkRegistrationInfo.Builder();
+    method @NonNull public android.telephony.NetworkRegistrationInfo build();
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
+  }
+
   public class ServiceState implements android.os.Parcelable {
+    method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
     method public void setCdmaSystemAndNetworkId(int, int);
     method public void setCellBandwidths(int[]);
     method public void setChannelNumber(int);
+    method public void setDataRoamingType(int);
     method public void setRilDataRadioTechnology(int);
     method public void setRilVoiceRadioTechnology(int);
+    method public void setVoiceRoamingType(int);
   }
 
   public class TelephonyManager {
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 24331af..55b1003 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -196,13 +196,7 @@
 
   std::stringstream stream;
   for (const auto& overlay : interesting_apks) {
-    std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
-    for (const std::string& policy : overlay.policies) {
-      verify_args.emplace_back("--policy");
-      verify_args.emplace_back(policy);
-    }
-
-    if (!Verify(std::vector<std::string>(verify_args))) {
+    if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}))) {
       std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
                                               "--overlay-apk-path", overlay.apk_path,
                                               "--idmap-path",       overlay.idmap_path};
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 2a3eee2..16c936c 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -84,4 +84,6 @@
     optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
 
     optional bool allow_from_any_uid = 50003 [default = false];
+
+    optional string log_from_module = 50004;
 }
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1735b05..d6ea7e6 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -40,6 +40,7 @@
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
 import "frameworks/base/core/proto/android/service/usb.proto";
+import "frameworks/base/core/proto/android/stats/connectivity/network_stack.proto";
 import "frameworks/base/core/proto/android/stats/enums.proto";
 import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
 import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
@@ -252,6 +253,7 @@
         StyleUIChanged style_ui_changed = 179;
         PrivacyIndicatorsInteracted privacy_indicators_interacted = 180;
         AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
+        NetworkStackReported network_stack_reported = 182;
     }
 
     // Pulled events will start at field 10000.
@@ -5851,3 +5853,14 @@
     // Size of the system ion heap in bytes.
     optional int64 size_in_bytes = 1;
 }
+
+/**
+ * Push network stack events.
+ *
+ * Log from:
+ *     frameworks/base/packages/NetworkStack/
+ */
+message NetworkStackReported {
+    optional int32 eventId = 1;
+    optional android.stats.connectivity.NetworkStackEventData network_stack_event = 2 [(log_mode) = MODE_BYTES];
+}
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index d740961..a3776c4 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -4759,7 +4759,6 @@
 HPLandroid/os/IDeviceIdleController$Stub$Proxy;->addPowerSaveTempWhitelistAppForSms(Ljava/lang/String;ILjava/lang/String;)J
 HPLandroid/os/IDeviceIdleController$Stub;->getDefaultTransactionName(I)Ljava/lang/String;
 HPLandroid/os/IDeviceIdleController$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
-HPLandroid/os/IDynamicAndroidService$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
 HPLandroid/os/IHardwarePropertiesManager$Stub;->getDefaultTransactionName(I)Ljava/lang/String;
 HPLandroid/os/IHardwarePropertiesManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
 HPLandroid/os/IInstalld$Stub$Proxy;->clearAppData(Ljava/lang/String;Ljava/lang/String;IIJ)V
@@ -5081,6 +5080,7 @@
 HPLandroid/os/health/HealthStatsWriter;->writeParcelableMap(Landroid/os/Parcel;Landroid/util/ArrayMap;)V
 HPLandroid/os/health/TimerStat;-><init>(IJ)V
 HPLandroid/os/health/TimerStat;->writeToParcel(Landroid/os/Parcel;I)V
+HPLandroid/os/image/IDynamicSystemService$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
 HPLandroid/os/storage/IStorageEventListener$Stub$Proxy;->onStorageStateChanged(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 HPLandroid/os/storage/IStorageManager$Stub$Proxy;->allocateBytes(Ljava/lang/String;JILjava/lang/String;)V
 HPLandroid/os/storage/IStorageManager$Stub$Proxy;->changeEncryptionPassword(ILjava/lang/String;)I
@@ -24027,7 +24027,6 @@
 HSPLandroid/os/IDeviceIdleController$Stub;-><init>()V
 HSPLandroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController;
 HSPLandroid/os/IDumpstate$Stub;-><init>()V
-HSPLandroid/os/IDynamicAndroidService$Stub;-><init>()V
 HSPLandroid/os/IExternalVibratorService$Stub;-><init>()V
 HSPLandroid/os/IHardwarePropertiesManager$Stub;-><init>()V
 HSPLandroid/os/IIncidentCompanion$Stub;-><init>()V
@@ -24837,6 +24836,7 @@
 HSPLandroid/os/ZygoteProcess;->zygoteSendArgsAndGetResult(Landroid/os/ZygoteProcess$ZygoteState;ZLjava/util/ArrayList;)Landroid/os/Process$ProcessStartResult;
 HSPLandroid/os/health/HealthStatsParceler$1;-><init>()V
 HSPLandroid/os/health/TimerStat$1;-><init>()V
+HSPLandroid/os/image/IDynamicSystemService$Stub;-><init>()V
 HSPLandroid/os/storage/IStorageEventListener$Stub$Proxy;->asBinder()Landroid/os/IBinder;
 HSPLandroid/os/storage/IStorageEventListener$Stub;->asBinder()Landroid/os/IBinder;
 HSPLandroid/os/storage/IStorageManager$Stub$Proxy;->getVolumeList(ILjava/lang/String;I)[Landroid/os/storage/StorageVolume;
@@ -47386,7 +47386,6 @@
 Landroid/os/DropBoxManager$Entry$1;
 Landroid/os/DropBoxManager$Entry;
 Landroid/os/DropBoxManager;
-Landroid/os/DynamicAndroidManager;
 Landroid/os/Environment$UserEnvironment;
 Landroid/os/Environment;
 Landroid/os/EventLogTags;
@@ -47428,8 +47427,6 @@
 Landroid/os/IDeviceIdleController;
 Landroid/os/IDumpstate$Stub;
 Landroid/os/IDumpstate;
-Landroid/os/IDynamicAndroidService$Stub;
-Landroid/os/IDynamicAndroidService;
 Landroid/os/IExternalVibratorService$Stub;
 Landroid/os/IExternalVibratorService;
 Landroid/os/IHardwarePropertiesManager$Stub;
@@ -47689,6 +47686,10 @@
 Landroid/os/health/SystemHealthManager;
 Landroid/os/health/TimerStat$1;
 Landroid/os/health/TimerStat;
+Landroid/os/image/DynamicSystemClient;
+Landroid/os/image/DynamicSystemManager;
+Landroid/os/image/IDynamicSystemService$Stub;
+Landroid/os/image/IDynamicSystemService;
 Landroid/os/storage/DiskInfo;
 Landroid/os/storage/IObbActionListener$Stub;
 Landroid/os/storage/IObbActionListener;
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 76d69cd..79cdb77 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1680,7 +1680,6 @@
 Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String;
 Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V
 Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V
-Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V
 Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J
 Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V
 Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V
diff --git a/config/preloaded-classes b/config/preloaded-classes
index fda028d..abdbab2 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2724,7 +2724,6 @@
 android.os.DropBoxManager$Entry$1
 android.os.DropBoxManager$Entry
 android.os.DropBoxManager
-android.os.DynamicAndroidManager
 android.os.Environment$UserEnvironment
 android.os.Environment
 android.os.EventLogTags
@@ -2909,6 +2908,8 @@
 android.os.health.SystemHealthManager
 android.os.health.TimerStat$1
 android.os.health.TimerStat
+android.os.image.DynamicSystemClient
+android.os.image.DynamicSystemManager
 android.os.storage.IObbActionListener$Stub
 android.os.storage.IObbActionListener
 android.os.storage.IStorageManager$Stub$Proxy
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7a0639e..404e520 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -536,6 +536,19 @@
         }
     }
 
+    @NonNull
+    @Override
+    public List<SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String packageName,
+            @InstallFlags int flags) {
+        try {
+            ParceledListSlice<SharedLibraryInfo> sharedLibraries = mPM.getDeclaredSharedLibraries(
+                    packageName, flags, mContext.getUserId());
+            return sharedLibraries != null ? sharedLibraries.getList() : Collections.emptyList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     @Override
     public @NonNull String getServicesSystemSharedLibraryPackageName() {
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index ec2825e..7180c01 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -231,7 +231,7 @@
      * Sets the zen policy.
      */
     public void setZenPolicy(ZenPolicy zenPolicy) {
-        this.mZenPolicy = zenPolicy;
+        this.mZenPolicy = (zenPolicy == null ? null : zenPolicy.copy());
     }
 
     /**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5945eef..11000df 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1090,7 +1090,6 @@
     @Override
     public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
             String[] receiverPermissions) {
-        warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
             intent.prepareToLeaveProcess(this);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7ba6146..d634aa5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -21,6 +21,7 @@
 import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
 
 import android.annotation.ColorInt;
+import android.annotation.DimenRes;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
@@ -8521,6 +8522,7 @@
         private PendingIntent mDeleteIntent;
         private Icon mIcon;
         private int mDesiredHeight;
+        @DimenRes private int mDesiredHeightResId;
         private int mFlags;
 
         /**
@@ -8547,10 +8549,11 @@
         private static final int FLAG_SUPPRESS_INITIAL_NOTIFICATION = 0x00000002;
 
         private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
-                Icon icon, int height) {
+                Icon icon, int height, @DimenRes int heightResId) {
             mPendingIntent = expandIntent;
             mIcon = icon;
             mDesiredHeight = height;
+            mDesiredHeightResId = heightResId;
             mDeleteIntent = deleteIntent;
         }
 
@@ -8562,6 +8565,7 @@
             if (in.readInt() != 0) {
                 mDeleteIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
+            mDesiredHeightResId = in.readInt();
         }
 
         /**
@@ -8581,17 +8585,6 @@
         }
 
         /**
-         * @return the title that will appear along with the app content defined by
-         * {@link #getIntent()} for this bubble.
-         *
-         * @deprecated titles are no longer required or shown.
-         */
-        @Deprecated
-        public CharSequence getTitle() {
-            return "";
-        }
-
-        /**
          * @return the icon that will be displayed for this bubble when it is collapsed.
          */
         @NonNull
@@ -8600,7 +8593,7 @@
         }
 
         /**
-         * @return the ideal height for the floating window that app content defined by
+         * @return the ideal height, in DPs, for the floating window that app content defined by
          * {@link #getIntent()} for this bubble.
          */
         public int getDesiredHeight() {
@@ -8608,6 +8601,15 @@
         }
 
         /**
+         * @return the resId of ideal height for the floating window that app content defined by
+         * {@link #getIntent()} for this bubble.
+         */
+        @DimenRes
+        public int getDesiredHeightResId() {
+            return mDesiredHeightResId;
+        }
+
+        /**
          * @return whether this bubble should auto expand when it is posted.
          *
          * @see BubbleMetadata.Builder#setAutoExpandBubble(boolean)
@@ -8654,6 +8656,7 @@
             if (mDeleteIntent != null) {
                 mDeleteIntent.writeToParcel(out, 0);
             }
+            out.writeInt(mDesiredHeightResId);
         }
 
         private void setFlags(int flags) {
@@ -8668,6 +8671,7 @@
             private PendingIntent mPendingIntent;
             private Icon mIcon;
             private int mDesiredHeight;
+            @DimenRes private int mDesiredHeightResId;
             private int mFlags;
             private PendingIntent mDeleteIntent;
 
@@ -8691,19 +8695,6 @@
             }
 
             /**
-             * Sets the title that will appear along with the app content for this bubble.
-             *
-             * <p>A title is required and should expect to fit on a single line and make sense when
-             * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
-             *
-             * @deprecated titles are no longer required or shown.
-             */
-            @Deprecated
-            public BubbleMetadata.Builder setTitle(CharSequence title) {
-                return this;
-            }
-
-            /**
              * Sets the icon that will represent the bubble when it is collapsed.
              *
              * <p>An icon is required and should be representative of the content within the bubble.
@@ -8733,13 +8724,35 @@
             }
 
             /**
-             * Sets the desired height for the app content defined by
+             * Sets the desired height in DPs for the app content defined by
              * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
              * enough space on the screen or if the provided height is too small to be useful.
+             * <p>
+             * If {@link #setDesiredHeightResId(int)} was previously called on this builder, the
+             * previous value set will be cleared after calling this method, and this value will
+             * be used instead.
              */
             @NonNull
             public BubbleMetadata.Builder setDesiredHeight(int height) {
                 mDesiredHeight = Math.max(height, 0);
+                mDesiredHeightResId = 0;
+                return this;
+            }
+
+
+            /**
+             * Sets the desired height via resId for the app content defined by
+             * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
+             * enough space on the screen or if the provided height is too small to be useful.
+             * <p>
+             * If {@link #setDesiredHeight(int)} was previously called on this builder, the
+             * previous value set will be cleared after calling this method, and this value will
+             * be used instead.
+             */
+            @NonNull
+            public BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int heightResId) {
+                mDesiredHeightResId = heightResId;
+                mDesiredHeight = 0;
                 return this;
             }
 
@@ -8801,7 +8814,7 @@
                     throw new IllegalStateException("Must supply an icon for the bubble");
                 }
                 BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent,
-                        mIcon, mDesiredHeight);
+                        mIcon, mDesiredHeight, mDesiredHeightResId);
                 data.setFlags(mFlags);
                 return data;
             }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 1aacf96..0bec21f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -315,7 +315,8 @@
      * This tag should contain a localized name of the type of the zen rule provided by the
      * activity.
      */
-    public static final String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
+    public static final String META_DATA_AUTOMATIC_RULE_TYPE =
+            "android.service.zen.automatic.ruleType";
 
     /**
      * An optional {@code meta-data} tag for activities that handle
@@ -325,7 +326,7 @@
      * can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
      */
     public static final String META_DATA_RULE_INSTANCE_LIMIT =
-            "android.app.zen.automatic.ruleInstanceLimit";
+            "android.service.zen.automatic.ruleInstanceLimit";
 
     /** Value signifying that the user has not expressed a per-app visibility override value.
      * @hide */
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4d280b7..d67bfb6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -131,13 +131,11 @@
 import android.os.Build;
 import android.os.DeviceIdleManager;
 import android.os.DropBoxManager;
-import android.os.DynamicAndroidManager;
 import android.os.HardwarePropertiesManager;
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
 import android.os.IDumpstate;
-import android.os.IDynamicAndroidService;
 import android.os.IHardwarePropertiesManager;
 import android.os.IPowerManager;
 import android.os.IRecoverySystem;
@@ -155,6 +153,8 @@
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.os.health.SystemHealthManager;
+import android.os.image.DynamicSystemManager;
+import android.os.image.IDynamicSystemService;
 import android.os.storage.StorageManager;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
@@ -1275,15 +1275,15 @@
                                 IRollbackManager.Stub.asInterface(b));
                     }});
 
-        registerService(Context.DYNAMIC_ANDROID_SERVICE, DynamicAndroidManager.class,
-                new CachedServiceFetcher<DynamicAndroidManager>() {
+        registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class,
+                new CachedServiceFetcher<DynamicSystemManager>() {
                     @Override
-                    public DynamicAndroidManager createService(ContextImpl ctx)
+                    public DynamicSystemManager createService(ContextImpl ctx)
                             throws ServiceNotFoundException {
                         IBinder b = ServiceManager.getServiceOrThrow(
-                                Context.DYNAMIC_ANDROID_SERVICE);
-                        return new DynamicAndroidManager(
-                                IDynamicAndroidService.Stub.asInterface(b));
+                                Context.DYNAMIC_SYSTEM_SERVICE);
+                        return new DynamicSystemManager(
+                                IDynamicSystemService.Stub.asInterface(b));
                     }});
         //CHECKSTYLE:ON IndentationCheck
     }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index a929fe0..325a54b 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -1666,6 +1667,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
     public boolean setWallpaperComponent(ComponentName name) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 20e85e6..3660ddc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4358,6 +4358,7 @@
 
     /**
      * Disable text entry into notifications on secure keyguard screens (e.g. PIN/Pattern/Password).
+     * This flag has no effect starting from version {@link android.os.Build.VERSION_CODES#N}
      */
     public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 1 << 6;
 
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index d71d355..9929855 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -24,8 +24,12 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
@@ -33,13 +37,15 @@
 import android.os.Parcelable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.internal.widget.LockPatternUtils.CredentialType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * A class that represents the metrics of a password that are used to decide whether or not a
- * password meets the requirements.
+ * A class that represents the metrics of a credential that are used to decide whether or not a
+ * credential meets the requirements. If the credential is a pattern, only quality matters.
  *
  * {@hide}
  */
@@ -48,8 +54,6 @@
     // consider it a complex PIN/password.
     public static final int MAX_ALLOWED_SEQUENCE = 3;
 
-    // TODO(b/120536847): refactor isActivePasswordSufficient logic so that the actual password
-    // quality is not overwritten
     public int quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     public int length = 0;
     public int letters = 0;
@@ -222,6 +226,25 @@
     };
 
     /**
+     * Returnsthe {@code PasswordMetrics} for a given credential.
+     *
+     * If the credential is a pin or a password, equivalent to {@link #computeForPassword(byte[])}.
+     * {@code credential} cannot be null when {@code type} is
+     * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}.
+     */
+    public static PasswordMetrics computeForCredential(
+            @CredentialType int type, byte[] credential) {
+        if (type == CREDENTIAL_TYPE_PASSWORD) {
+            Preconditions.checkNotNull(credential, "credential cannot be null");
+            return PasswordMetrics.computeForPassword(credential);
+        } else if (type == CREDENTIAL_TYPE_PATTERN)  {
+            return new PasswordMetrics(PASSWORD_QUALITY_SOMETHING);
+        } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
+            return new PasswordMetrics(PASSWORD_QUALITY_UNSPECIFIED);
+        }
+    }
+
+    /**
      * Returns the {@code PasswordMetrics} for a given password
      */
     public static PasswordMetrics computeForPassword(@NonNull byte[] password) {
@@ -233,8 +256,8 @@
         int symbols = 0;
         int nonLetter = 0;
         final int length = password.length;
-        for (int i = 0; i < length; i++) {
-            switch (categoryChar((char) password[i])) {
+        for (byte b : password) {
+            switch (categoryChar((char) b)) {
                 case CHAR_LOWER_CASE:
                     letters++;
                     lowerCase++;
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 6386573..19f4335 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -136,8 +136,11 @@
     public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
 
     /**
-     * Indicates that keyguard has been dismissed.
+     * Indicates that keyguard has been dismissed. This event is only logged if the device
+     * has a secure keyguard. It is logged regardless of how keyguard is dismissed, including
+     * via PIN/pattern/password, biometrics or via a trust agent.
      * There is no extra payload in the log event.
+     * @see #TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT
      */
     public static final int TAG_KEYGUARD_DISMISSED = SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
 
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 3e4e8dc..3f2f209 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -131,14 +131,14 @@
      * @param launchLocation The launch location where the targets are shown to the user.
      * @param targetIds List of {@link AppTargetId}s that are shown to the user.
      */
-    public void notifyLocationShown(@NonNull String launchLocation,
+    public void notifyLaunchLocationShown(@NonNull String launchLocation,
             @NonNull List<AppTargetId> targetIds) {
         if (mIsClosed.get()) {
             throw new IllegalStateException("This client has already been destroyed.");
         }
 
         try {
-            mPredictionManager.notifyLocationShown(mSessionId, launchLocation,
+            mPredictionManager.notifyLaunchLocationShown(mSessionId, launchLocation,
                     new ParceledListSlice<>(targetIds));
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to notify location shown event", e);
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index bb1b96c..826c149 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -43,20 +43,13 @@
 
     private final ShortcutInfo mShortcutInfo;
 
-    private int mRank;
+    private final int mRank;
 
     /**
-     * Creates an instance of AppTarget that represent a launchable component.
-     *
-     * @param id A unique id for this launchable target.
-     * @param packageName Package name of the target.
-     * @param className Class name of the target.
-     * @param user The UserHandle of the user which this target belongs to.
-     *
+     * @deprecated use the Builder class
      * @hide
      */
-    @SystemApi
-    @TestApi
+    @Deprecated
     public AppTarget(@NonNull AppTargetId id, @NonNull String packageName,
             @Nullable String className, @NonNull UserHandle user) {
         mId = id;
@@ -65,18 +58,14 @@
         mPackageName = Preconditions.checkNotNull(packageName);
         mClassName = className;
         mUser = Preconditions.checkNotNull(user);
+        mRank = 0;
     }
 
     /**
-     * Creates an instance of AppTarget that represent a launchable shortcut.
-     *
-     * @param id A unique id for this launchable target.
-     * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target.
-     * @param className Class name fo the target.
-     *
+     * @deprecated use the Builder class
      * @hide
      */
-    @SystemApi
+    @Deprecated
     public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo,
             @Nullable String className) {
         mId = id;
@@ -85,6 +74,17 @@
         mPackageName = mShortcutInfo.getPackage();
         mUser = mShortcutInfo.getUserHandle();
         mClassName = className;
+        mRank = 0;
+    }
+
+    private AppTarget(AppTargetId id, String packageName, UserHandle user,
+            ShortcutInfo shortcutInfo, String className, int rank) {
+        mId = id;
+        mShortcutInfo = shortcutInfo;
+        mPackageName = packageName;
+        mClassName = className;
+        mUser = user;
+        mRank = rank;
     }
 
     private AppTarget(Parcel parcel) {
@@ -142,17 +142,6 @@
     }
 
     /**
-     * Sets the rank of the for the target.
-     * @hide
-     */
-    public void setRank(@IntRange(from = 0) int rank) {
-        if (rank < 0) {
-            throw new IllegalArgumentException("rank cannot be a negative value");
-        }
-        mRank = rank;
-    }
-
-    /**
      * Returns the rank for the target. Rank of an AppTarget is a non-negative integer that
      * represents the importance of this target compared to other candidate targets. A smaller value
      * means higher importance in the list.
@@ -196,6 +185,101 @@
         dest.writeInt(mRank);
     }
 
+    /**
+     * A builder for app targets.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final class Builder {
+
+        @NonNull
+        private final AppTargetId mId;
+
+        private String mPackageName;
+        private UserHandle mUser;
+        private ShortcutInfo mShortcutInfo;
+
+        private String mClassName;
+        private int mRank;
+
+        /**
+         * @param id A unique id for this launchable target.
+         * @hide
+         */
+        @SystemApi
+        @TestApi
+        public Builder(@NonNull AppTargetId id) {
+            mId = id;
+        }
+
+        /**
+         * Sets the target to be an app.
+         *
+         * @param packageName PackageName of the app
+         * @param user The UserHandle of the user which this target belongs to.
+         *
+         * @throws IllegalArgumentException is the target is already set
+         */
+        @NonNull
+        public Builder setTarget(@NonNull String packageName, @NonNull UserHandle user) {
+            if (mPackageName == null) {
+                throw new IllegalArgumentException("Target is already set");
+            }
+            mPackageName = Preconditions.checkNotNull(packageName);
+            mUser = Preconditions.checkNotNull(user);
+            return this;
+        }
+
+        /**
+         * Sets the target to be a ShortcutInfo.
+         *
+         * @throws IllegalArgumentException is the target is already set
+         */
+        @NonNull
+        public Builder setTarget(@NonNull ShortcutInfo info) {
+            setTarget(info.getPackage(), info.getUserHandle());
+            mShortcutInfo = Preconditions.checkNotNull(info);
+            return this;
+        }
+
+        /**
+         * Sets the className for the target
+         */
+        @NonNull
+        public Builder setClassName(@NonNull String className) {
+            mClassName = Preconditions.checkNotNull(className);
+            return this;
+        }
+
+        /**
+         * Sets the rank of the for the target.
+         */
+        @NonNull
+        public Builder setRank(@IntRange(from = 0) int rank) {
+            if (rank < 0) {
+                throw new IllegalArgumentException("rank cannot be a negative value");
+            }
+            mRank = rank;
+            return this;
+        }
+
+        /**
+         * Builds a new AppTarget instance.
+         *
+         * @throws IllegalStateException if no target is set
+         * @see #setTarget(ShortcutInfo)
+         * @see #setTarget(String, UserHandle)
+         */
+        @NonNull
+        public AppTarget build() {
+            if (mPackageName == null) {
+                throw new IllegalStateException("No target set");
+            }
+            return new AppTarget(mId, mPackageName, mUser, mShortcutInfo, mClassName, mRank);
+        }
+    }
+
     public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR =
             new Parcelable.Creator<AppTarget>() {
                 public AppTarget createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
index 114a1ff..587e3fd 100644
--- a/core/java/android/app/prediction/IPredictionManager.aidl
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -33,7 +33,7 @@
 
     void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
 
-    void notifyLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
+    void notifyLaunchLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
             in ParceledListSlice targetIds);
 
     void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java
index 6b7f10e..ac19504 100644
--- a/core/java/android/attention/AttentionManagerInternal.java
+++ b/core/java/android/attention/AttentionManagerInternal.java
@@ -50,6 +50,13 @@
      */
     public abstract void cancelAttentionCheck(int requestCode);
 
+    /**
+     * Disables the dependants.
+     *
+     * Example: called if the service does not have sufficient permissions to perform the task.
+     */
+    public abstract void disableSelf();
+
     /** Internal interface for attention callback. */
     public abstract static class AttentionCallbackInternal {
         /**
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 6be0bea..1727d34 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -72,9 +72,29 @@
     @Nullable
     public final ArraySet<ComponentName> whitelistedComponents;
 
+    /**
+     * Used to enable just a small set of APIs so it can used by activities belonging to the
+     * content capture service APK.
+     */
+    public final boolean lite;
+
+    public ContentCaptureOptions(int loggingLevel) {
+        this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
+                /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
+                /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
+    }
+
     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
             int textChangeFlushingFrequencyMs, int logHistorySize,
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
+                textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
+    }
+
+    private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
+            int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
+            @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this.lite = lite;
         this.loggingLevel = loggingLevel;
         this.maxBufferSize = maxBufferSize;
         this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
@@ -115,6 +135,9 @@
 
     @Override
     public String toString() {
+        if (lite) {
+            return "ContentCaptureOptions [(lite) loggingLevel=" + loggingLevel + "]";
+        }
         return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
                 + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
                 + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
@@ -125,6 +148,10 @@
     /** @hide */
     public void dumpShort(@NonNull PrintWriter pw) {
         pw.print("logLvl="); pw.print(loggingLevel);
+        if (lite) {
+            pw.print(", lite");
+            return;
+        }
         pw.print(", bufferSize="); pw.print(maxBufferSize);
         pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
         pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
@@ -141,7 +168,10 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeBoolean(lite);
         parcel.writeInt(loggingLevel);
+        if (lite) return;
+
         parcel.writeInt(maxBufferSize);
         parcel.writeInt(idleFlushingFrequencyMs);
         parcel.writeInt(textChangeFlushingFrequencyMs);
@@ -154,7 +184,11 @@
 
                 @Override
                 public ContentCaptureOptions createFromParcel(Parcel parcel) {
+                    final boolean lite = parcel.readBoolean();
                     final int loggingLevel = parcel.readInt();
+                    if (lite) {
+                        return new ContentCaptureOptions(loggingLevel);
+                    }
                     final int maxBufferSize = parcel.readInt();
                     final int idleFlushingFrequencyMs = parcel.readInt();
                     final int textChangeFlushingFrequencyMs = parcel.readInt();
@@ -171,6 +205,5 @@
                 public ContentCaptureOptions[] newArray(int size) {
                     return new ContentCaptureOptions[size];
                 }
-
     };
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fb933b1..d7a2e1b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -338,6 +338,14 @@
     public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
 
     /**
+     * Flag for {@link #bindService}: If binding from an app that has specific capabilities
+     * due to its foreground state such as an activity or foreground service, then this flag will
+     * allow the bound app to get the same capabilities, as long as it has the required permissions
+     * as well.
+     */
+    public static final int BIND_INCLUDE_CAPABILITIES = 0x00001000;
+
+    /**
      * Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
      * the scheduling policy for IMEs (and any other out-of-process user-visible components that
      * work closely with the top app) so that UI hosted in such services can have the same
@@ -4644,11 +4652,10 @@
 
      /**
      * Use with {@link #getSystemService(String)} to retrieve an
-     * {@link android.os.DynamicAndroidManager}.
+     * {@link android.os.image.DynamicSystemManager}.
      * @hide
      */
-    @SystemApi
-    public static final String DYNAMIC_ANDROID_SERVICE = "dynamic_android";
+    public static final String DYNAMIC_SYSTEM_SERVICE = "dynamic_system";
 
     /**
      * Determine whether the given permission is allowed for a particular
@@ -5322,6 +5329,7 @@
      * @return display ID associated with this {@link Context}.
      * @hide
      */
+    @TestApi
     public abstract int getDisplayId();
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6bb9498..a5f627d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2118,29 +2118,6 @@
             "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
 
     /**
-     * Activity action: Launch UI to review uses of permissions for a single app.
-     * <p>
-     * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
-     * permissions will be reviewed (mandatory).
-     * </p>
-     * <p>
-     * Output: Nothing.
-     * </p>
-     * <p class="note">
-     * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission.
-     * </p>
-     *
-     * @see #EXTRA_PACKAGE_NAME
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_REVIEW_APP_PERMISSION_USAGE =
-            "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
-
-    /**
      * Activity action: Launch UI to review running accessibility services.
      * <p>
      * Input: Nothing.
@@ -3500,6 +3477,7 @@
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
      */
+    @SystemApi
     public static final String ACTION_USER_ADDED =
             "android.intent.action.USER_ADDED";
 
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 999d986..aabe59d 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -18,12 +18,14 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Immutable overlay information about a package. All PackageInfos that
@@ -138,6 +140,14 @@
     public final String targetPackageName;
 
     /**
+     * Name of the target overlayable declaration.
+     *
+     * @hide
+     */
+    @SystemApi
+    public final String targetOverlayableName;
+
+    /**
      * Category of the overlay package
      *
      * @hide
@@ -190,16 +200,19 @@
      * @hide
      */
     public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
-        this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
-                state, source.userId, source.priority, source.isStatic);
+        this(source.packageName, source.targetPackageName, source.targetOverlayableName,
+                source.category, source.baseCodePath, state, source.userId, source.priority,
+                source.isStatic);
     }
 
     /** @hide */
     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
-            @NonNull String category, @NonNull String baseCodePath, int state, int userId,
+            @Nullable String targetOverlayableName, @Nullable String category,
+            @NonNull String baseCodePath, int state, int userId,
             int priority, boolean isStatic) {
         this.packageName = packageName;
         this.targetPackageName = targetPackageName;
+        this.targetOverlayableName = targetOverlayableName;
         this.category = category;
         this.baseCodePath = baseCodePath;
         this.state = state;
@@ -213,6 +226,7 @@
     public OverlayInfo(Parcel source) {
         packageName = source.readString();
         targetPackageName = source.readString();
+        targetOverlayableName = source.readString();
         category = source.readString();
         baseCodePath = source.readString();
         state = source.readInt();
@@ -256,6 +270,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(packageName);
         dest.writeString(targetPackageName);
+        dest.writeString(targetOverlayableName);
         dest.writeString(category);
         dest.writeString(baseCodePath);
         dest.writeInt(state);
@@ -335,6 +350,8 @@
         result = prime * result + state;
         result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
         result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode());
+        result = prime * result + ((targetOverlayableName == null) ? 0
+                : targetOverlayableName.hashCode());
         result = prime * result + ((category == null) ? 0 : category.hashCode());
         result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode());
         return result;
@@ -364,7 +381,10 @@
         if (!targetPackageName.equals(other.targetPackageName)) {
             return false;
         }
-        if (!category.equals(other.category)) {
+        if (!Objects.equals(targetOverlayableName, other.targetOverlayableName)) {
+            return false;
+        }
+        if (!Objects.equals(category, other.category)) {
             return false;
         }
         if (!baseCodePath.equals(other.baseCodePath)) {
@@ -375,7 +395,9 @@
 
     @Override
     public String toString() {
-        return "OverlayInfo { overlay=" + packageName + ", target=" + targetPackageName + ", state="
-                + state + " (" + stateToString(state) + "), userId=" + userId + " }";
+        return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
+                + ((targetOverlayableName == null) ? ""
+                : ", targetOverlyabale=" + targetOverlayableName)
+                + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }";
     }
 }
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index ceea043..f2716fe 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
@@ -61,40 +62,57 @@
      * Request that an overlay package is enabled and any other overlay packages with the same
      * target package and category are disabled.
      *
+     * If a set of overlay packages share the same category, single call to this method is
+     * equivalent to multiple calls to {@link #setEnabled(String, boolean, UserHandle)}.
+     *
      * @param packageName the name of the overlay package to enable.
-     * @param userId The user for which to change the overlay.
-     * @return true if the system successfully registered the request, false otherwise.
+     * @param user The user for which to change the overlay.
      *
      * @hide
      */
     @SystemApi
-    public boolean setEnabledExclusiveInCategory(@Nullable final String packageName,
-            int userId) {
+    @RequiresPermission(anyOf = {
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.INTERACT_ACROSS_USERS_FULL"
+    })
+    public void setEnabledExclusiveInCategory(@NonNull final String packageName,
+            @NonNull UserHandle user) {
         try {
-            return mService.setEnabledExclusiveInCategory(packageName, userId);
+            if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) {
+                throw new IllegalStateException("setEnabledExclusiveInCategory failed");
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Request that an overlay package is enabled.
+     * Request that an overlay package is enabled or disabled.
+     *
+     * While {@link #setEnabledExclusiveInCategory(String, UserHandle)} doesn't support disabling
+     * every overlay in a category, this method allows you to disable everything.
      *
      * @param packageName the name of the overlay package to enable.
      * @param enable {@code false} if the overlay should be turned off.
-     * @param userId The user for which to change the overlay.
-     * @return true if the system successfully registered the request, false otherwise.
+     * @param user The user for which to change the overlay.
      *
      * @hide
      */
     @SystemApi
-    public boolean setEnabled(@Nullable final String packageName, final boolean enable,
-            int userId) {
+    @RequiresPermission(anyOf = {
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.INTERACT_ACROSS_USERS_FULL"
+    })
+    public void setEnabled(@NonNull final String packageName, final boolean enable,
+            @NonNull UserHandle user) {
         try {
-            return mService.setEnabled(packageName, enable, userId);
+            if (!mService.setEnabled(packageName, enable, user.getIdentifier())) {
+                throw new IllegalStateException("setEnabled failed");
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+        return;
     }
 
     /**
@@ -113,7 +131,7 @@
     public OverlayInfo getOverlayInfo(@NonNull final String packageName,
             @NonNull final UserHandle userHandle) {
         try {
-            return mService.getOverlayInfo(packageName, userHandle.myUserId());
+            return mService.getOverlayInfo(packageName, userHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -125,17 +143,22 @@
      * overlay priority with the highest priority at the end of the list.
      *
      * @param targetPackageName The name of the target package.
-     * @param userId The user to get the OverlayInfos for.
+     * @param user The user to get the OverlayInfos for.
      * @return A list of OverlayInfo objects; if no overlays exist for the
      *         requested package, an empty list is returned.
      *
      * @hide
      */
     @SystemApi
-    public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
-            int userId) {
+    @RequiresPermission(anyOf = {
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.INTERACT_ACROSS_USERS_FULL"
+    })
+    @NonNull
+    public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName,
+            @NonNull UserHandle user) {
         try {
-            return mService.getOverlayInfosForTarget(targetPackageName, userId);
+            return mService.getOverlayInfosForTarget(targetPackageName, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 464e866..c798270 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -714,6 +714,8 @@
 
     ParceledListSlice getSharedLibraries(in String packageName, int flags, int userId);
 
+    ParceledListSlice getDeclaredSharedLibraries(in String packageName, int flags, int userId);
+
     boolean canRequestPackageInstalls(String packageName, int userId);
 
     void deletePreloadsFileCache();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 725d601..d6fb28f 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -354,12 +354,12 @@
     public String overlayTarget;
 
     /**
-     * What overlayable set of elements package, if any, this package will overlay.
+     * The name of the overlayable set of elements package, if any, this package will overlay.
      *
      * Overlayable name defined within the target package, or null.
      * @hide
      */
-    public String overlayTargetName;
+    public String targetOverlayableName;
 
     /**
      * The overlay category, if any, of this package
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 73e6f67..961faa0c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4239,6 +4239,24 @@
             @InstallFlags int flags, @UserIdInt int userId);
 
     /**
+     * Get the list of shared libraries declared by a package.
+     *
+     * @param packageName the package name to query
+     * @param flags the flags to filter packages
+     * @return the shared library list
+     *
+     * @hide
+     */
+    @NonNull
+    @RequiresPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES)
+    @SystemApi
+    public List<SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String packageName,
+            @InstallFlags int flags) {
+        throw new UnsupportedOperationException(
+                "getDeclaredSharedLibraries() not implemented in subclass");
+    }
+
+    /**
      * Get the name of the package hosting the services shared library.
      *
      * @return The library host package.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 743a302..b480939 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -689,7 +689,7 @@
         pi.restrictedAccountType = p.mRestrictedAccountType;
         pi.requiredAccountType = p.mRequiredAccountType;
         pi.overlayTarget = p.mOverlayTarget;
-        pi.overlayTargetName = p.mOverlayTargetName;
+        pi.targetOverlayableName = p.mOverlayTargetName;
         pi.overlayCategory = p.mOverlayCategory;
         pi.overlayPriority = p.mOverlayPriority;
         pi.mOverlayIsStatic = p.mOverlayIsStatic;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6b8416d..d7e4e14 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1721,8 +1721,6 @@
          * Rebases the theme against the parent Resource object's current
          * configuration by re-applying the styles passed to
          * {@link #applyStyle(int, boolean)}.
-         *
-         * @hide
          */
         public void rebase() {
             mThemeImpl.rebase();
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index 3e4e35a..1339432 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -64,8 +64,6 @@
     private final IBinder mBinder;
 
     /** @hide */
-    @SystemApi
-    @TestApi
     public CaptivePortal(@NonNull IBinder binder) {
         mBinder = binder;
     }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1632235..428c2e7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -4101,9 +4101,12 @@
      * @hide
      */
     @SystemApi
-    public boolean getAvoidBadWifi() {
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    public boolean shouldAvoidBadWifi() {
         try {
-            return mService.getAvoidBadWifi();
+            return mService.shouldAvoidBadWifi();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 93b8cf8..5980251 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import static android.net.NetworkUtils.resNetworkCancel;
 import static android.net.NetworkUtils.resNetworkQuery;
 import static android.net.NetworkUtils.resNetworkResult;
 import static android.net.NetworkUtils.resNetworkSend;
@@ -26,6 +27,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.CancellationSignal;
 import android.os.Looper;
 import android.system.ErrnoException;
 import android.util.Log;
@@ -191,11 +193,18 @@
      * @param query blob message
      * @param flags flags as a combination of the FLAGS_* constants
      * @param executor The {@link Executor} that the callback should be executed on.
+     * @param cancellationSignal used by the caller to signal if the query should be
+     *    cancelled. May be {@code null}.
      * @param callback an {@link AnswerCallback} which will be called to notify the caller
-     *         of the result of dns query.
+     *    of the result of dns query.
      */
     public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
-            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull AnswerCallback<T> callback) {
+        if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+            return;
+        }
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkSend((network != null
@@ -205,6 +214,7 @@
             return;
         }
 
+        maybeAddCancellationSignal(cancellationSignal, queryfd);
         registerFDListener(executor, queryfd, callback);
     }
 
@@ -219,12 +229,19 @@
      * @param nsType dns resource record (RR) type as one of the TYPE_* constants
      * @param flags flags as a combination of the FLAGS_* constants
      * @param executor The {@link Executor} that the callback should be executed on.
+     * @param cancellationSignal used by the caller to signal if the query should be
+     *    cancelled. May be {@code null}.
      * @param callback an {@link AnswerCallback} which will be called to notify the caller
-     *         of the result of dns query.
+     *    of the result of dns query.
      */
     public <T> void query(@Nullable Network network, @NonNull String domain,
             @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
-            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull AnswerCallback<T> callback) {
+        if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+            return;
+        }
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
@@ -233,6 +250,8 @@
             callback.onQueryException(e);
             return;
         }
+
+        maybeAddCancellationSignal(cancellationSignal, queryfd);
         registerFDListener(executor, queryfd, callback);
     }
 
@@ -264,6 +283,17 @@
                 });
     }
 
+    private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
+            @NonNull FileDescriptor queryfd) {
+        if (cancellationSignal == null) return;
+        cancellationSignal.setOnCancelListener(
+                () -> {
+                    Looper.getMainLooper().getQueue()
+                            .removeOnFileDescriptorEventListener(queryfd);
+                    resNetworkCancel(queryfd);
+            });
+    }
+
     private static class DnsAddressAnswer extends DnsPacket {
         private static final String TAG = "DnsResolver.DnsAddressAnswer";
         private static final boolean DBG = false;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 24e6a85..61648dc 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -182,7 +182,7 @@
     void startCaptivePortalApp(in Network network);
     void startCaptivePortalAppInternal(in Network network, in Bundle appExtras);
 
-    boolean getAvoidBadWifi();
+    boolean shouldAvoidBadWifi();
     int getMultipathPreference(in Network Network);
 
     NetworkRequest getDefaultRequest();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index ed410e2..5188866 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -177,6 +177,12 @@
     public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException;
 
     /**
+     * DNS resolver series jni method.
+     * Attempts to cancel the in-progress query associated with the {@code fd}.
+     */
+    public static native void resNetworkCancel(FileDescriptor fd);
+
+    /**
      * Add an entry into the ARP cache.
      */
     public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname,
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 320f471..b92e713 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -92,6 +92,13 @@
     public static final String EXTRA_TIME = "time";
 
     /**
+     * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}:
+     * integer value containing number of broadcasts dropped due to rate limiting on
+     * this {@link android.os.DropBoxManager#EXTRA_TAG}
+     */
+    public static final String EXTRA_DROPPED_COUNT = "android.os.extra.DROPPED_COUNT";
+
+    /**
      * A single entry retrieved from the drop box.
      * This may include a reference to a stream, so you must call
      * {@link #close()} when you are done using it.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 707a404..41691d7 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -63,7 +63,7 @@
     private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
     private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
-    private static final String METADATA_DRIVER_BUILD_TIME = "driver_build_time";
+    private static final String METADATA_DRIVER_BUILD_TIME = "com.android.gamedriver.build_time";
     private static final String ANGLE_RULES_FILE = "a4a_rules.json";
     private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
     private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
@@ -702,7 +702,7 @@
 
         final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
         if (driverBuildTime == null || driverBuildTime.isEmpty()) {
-            throw new IllegalArgumentException("driver_build_time meta-data is not set");
+            throw new IllegalArgumentException("com.android.gamedriver.build_time is not set");
         }
         // driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
         // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index b5c6604..e1d605e 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -53,10 +53,10 @@
     boolean isPowerSaveMode();
     PowerSaveState getPowerSaveState(int serviceType);
     boolean setPowerSaveModeEnabled(boolean mode);
-    boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled, int disableThreshold);
+    boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold);
     boolean setAdaptivePowerSavePolicy(in BatterySaverPolicyConfig config);
     boolean setAdaptivePowerSaveEnabled(boolean enabled);
-    int getPowerSaveMode();
+    int getPowerSaveModeTrigger();
     boolean isDeviceIdleMode();
     boolean isLightDeviceIdleMode();
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 36bae2d..64e2f89 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1460,7 +1460,7 @@
      * an on/off switch for a subset of features.
      * @hide
      *
-     * @param dynamicPowerSavingsEnabled A signal indicating to the system if it believes the
+     * @param powerSaveHint A signal indicating to the system if it believes the
      * dynamic power savings behaviors should be activated.
      * @param disableThreshold When the suggesting app believes it would be safe to disable dynamic
      * power savings behaviors.
@@ -1471,10 +1471,9 @@
     @SystemApi
     @TestApi
     @RequiresPermission(permission.POWER_SAVER)
-    public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
-            int disableThreshold) {
+    public boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold) {
         try {
-            return mService.setDynamicPowerSavings(dynamicPowerSavingsEnabled, disableThreshold);
+            return mService.setDynamicPowerSaveHint(powerSaveHint, disableThreshold);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1525,54 +1524,54 @@
     /**
      * Indicates automatic battery saver toggling by the system will be based on percentage.
      *
-     * @see PowerManager#getPowerSaveMode()
+     * @see PowerManager#getPowerSaveModeTrigger()
      *
      *  @hide
      */
     @SystemApi
     @TestApi
-    public static final int POWER_SAVER_MODE_PERCENTAGE = 0;
+    public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0;
 
     /**
      * Indicates automatic battery saver toggling by the system will be based on the state
      * of the dynamic power savings signal.
      *
-     * @see PowerManager#setDynamicPowerSavings(boolean, int)
-     * @see PowerManager#getPowerSaveMode()
+     * @see PowerManager#setDynamicPowerSaveHint(boolean, int)
+     * @see PowerManager#getPowerSaveModeTrigger()
      *
      *  @hide
      */
     @SystemApi
     @TestApi
-    public static final int POWER_SAVER_MODE_DYNAMIC = 1;
+    public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
-        POWER_SAVER_MODE_PERCENTAGE,
-        POWER_SAVER_MODE_DYNAMIC
+        POWER_SAVE_MODE_TRIGGER_PERCENTAGE,
+        POWER_SAVE_MODE_TRIGGER_DYNAMIC
 
     })
-    public @interface AutoPowerSaverMode{}
+    public @interface AutoPowerSaveModeTriggers {}
 
 
     /**
      * Returns the current battery saver control mode. Values it may return are defined in
-     * AutoPowerSaverMode. Note that this is a global device state, not a per user setting.
+     * AutoPowerSaveModeTriggers. Note that this is a global device state, not a per user setting.
      *
      * @return The current value power saver mode for the system.
      *
-     * @see AutoPowerSaverMode
-     * @see PowerManager#getPowerSaveMode()
+     * @see AutoPowerSaveModeTriggers
+     * @see PowerManager#getPowerSaveModeTrigger()
      * @hide
      */
-    @AutoPowerSaverMode
+    @AutoPowerSaveModeTriggers
     @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.POWER_SAVER)
-    public int getPowerSaveMode() {
+    public int getPowerSaveModeTrigger() {
         try {
-            return mService.getPowerSaveMode();
+            return mService.getPowerSaveModeTrigger();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index c74cbff..7958ddd 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -23,7 +23,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.hardware.vibrator.V1_0.EffectStrength;
-import android.hardware.vibrator.V1_2.Effect;
+import android.hardware.vibrator.V1_3.Effect;
 import android.net.Uri;
 import android.util.MathUtils;
 
@@ -94,6 +94,18 @@
      */
     public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
 
+    /**
+     * A texture effect meant to replicate soft ticks.
+     *
+     * Unlike normal effects, texture effects are meant to be called repeatedly, generally in
+     * response to some motion, in order to replicate the feeling of some texture underneath the
+     * user's fingers.
+     *
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_TEXTURE_TICK = Effect.TEXTURE_TICK;
+
     /** {@hide} */
     @TestApi
     public static final int EFFECT_STRENGTH_LIGHT = EffectStrength.LIGHT;
@@ -746,6 +758,7 @@
                 case EFFECT_CLICK:
                 case EFFECT_DOUBLE_CLICK:
                 case EFFECT_TICK:
+                case EFFECT_TEXTURE_TICK:
                 case EFFECT_THUD:
                 case EFFECT_POP:
                 case EFFECT_HEAVY_CLICK:
@@ -798,7 +811,7 @@
             out.writeInt(mEffectStrength);
         }
 
-        public static final @android.annotation.NonNull Parcelable.Creator<Prebaked> CREATOR =
+        public static final @NonNull Parcelable.Creator<Prebaked> CREATOR =
             new Parcelable.Creator<Prebaked>() {
                 @Override
                 public Prebaked createFromParcel(Parcel in) {
@@ -813,7 +826,7 @@
             };
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<VibrationEffect> CREATOR =
+    public static final @NonNull Parcelable.Creator<VibrationEffect> CREATOR =
             new Parcelable.Creator<VibrationEffect>() {
                 @Override
                 public VibrationEffect createFromParcel(Parcel in) {
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 40238d2..915baab 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -66,22 +66,14 @@
  */
 public class ZygoteProcess {
 
-    /**
-     * @hide for internal use only.
-     */
-    public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
+    private static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
 
     /**
-     * @hide for internal use only.
-     *
      * Use a relatively short delay, because for app zygote, this is in the critical path of
      * service launch.
      */
-    public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
+    private static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
 
-    /**
-     * @hide for internal use only
-     */
     private static final String LOG_TAG = "ZygoteProcess";
 
     /**
@@ -141,7 +133,7 @@
     /**
      * State for communicating with the zygote process.
      */
-    public static class ZygoteState {
+    private static class ZygoteState implements AutoCloseable {
         final LocalSocketAddress mZygoteSocketAddress;
         final LocalSocketAddress mUsapSocketAddress;
 
@@ -178,12 +170,12 @@
          * address
          * @throws IOException
          */
-        public static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
-                                          @Nullable LocalSocketAddress usapSocketAddress)
+        static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
+                @Nullable LocalSocketAddress usapSocketAddress)
                 throws IOException {
 
-            DataInputStream zygoteInputStream = null;
-            BufferedWriter zygoteOutputWriter = null;
+            DataInputStream zygoteInputStream;
+            BufferedWriter zygoteOutputWriter;
             final LocalSocket zygoteSessionSocket = new LocalSocket();
 
             if (zygoteSocketAddress == null) {
@@ -357,8 +349,6 @@
 
     /**
      * Queries the zygote for the list of ABIS it supports.
-     *
-     * @throws ZygoteStartFailedEx if the query failed.
      */
     @GuardedBy("mLock")
     private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
@@ -411,52 +401,24 @@
          * the child or -1 on failure, followed by boolean to
          * indicate whether a wrapper process was used.
          */
-        String msgStr = Integer.toString(args.size()) + "\n"
-                        + String.join("\n", args) + "\n";
+        String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
 
-        // Should there be a timeout on this?
-        Process.ProcessStartResult result = new Process.ProcessStartResult();
-
-        // TODO (chriswailes): Move branch body into separate function.
         if (useUsapPool && mUsapPoolEnabled && isValidUsapCommand(args)) {
-            LocalSocket usapSessionSocket = null;
-
             try {
-                usapSessionSocket = zygoteState.getUsapSessionSocket();
-
-                final BufferedWriter usapWriter =
-                        new BufferedWriter(
-                                new OutputStreamWriter(usapSessionSocket.getOutputStream()),
-                                Zygote.SOCKET_BUFFER_SIZE);
-                final DataInputStream usapReader =
-                        new DataInputStream(usapSessionSocket.getInputStream());
-
-                usapWriter.write(msgStr);
-                usapWriter.flush();
-
-                result.pid = usapReader.readInt();
-                // USAPs can't be used to spawn processes that need wrappers.
-                result.usingWrapper = false;
-
-                if (result.pid < 0) {
-                    throw new ZygoteStartFailedEx("USAP specialization failed");
-                }
-
-                return result;
+                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
             } catch (IOException ex) {
                 // If there was an IOException using the USAP pool we will log the error and
                 // attempt to start the process through the Zygote.
                 Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
-                               + ex.getMessage());
-            } finally {
-                try {
-                    usapSessionSocket.close();
-                } catch (IOException ex) {
-                    Log.e(LOG_TAG, "Failed to close USAP session socket: " + ex.getMessage());
-                }
+                        + ex.getMessage());
             }
         }
 
+        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
+    }
+
+    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
+            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
         try {
             final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
             final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
@@ -467,20 +429,48 @@
             // Always read the entire result from the input stream to avoid leaving
             // bytes in the stream for future process starts to accidentally stumble
             // upon.
+            Process.ProcessStartResult result = new Process.ProcessStartResult();
             result.pid = zygoteInputStream.readInt();
             result.usingWrapper = zygoteInputStream.readBoolean();
+
+            if (result.pid < 0) {
+                throw new ZygoteStartFailedEx("fork() failed");
+            }
+
+            return result;
         } catch (IOException ex) {
             zygoteState.close();
             Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                     + ex.toString());
             throw new ZygoteStartFailedEx(ex);
         }
+    }
 
-        if (result.pid < 0) {
-            throw new ZygoteStartFailedEx("fork() failed");
+    private Process.ProcessStartResult attemptUsapSendArgsAndGetResult(
+            ZygoteState zygoteState, String msgStr)
+            throws ZygoteStartFailedEx, IOException {
+        try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
+            final BufferedWriter usapWriter =
+                    new BufferedWriter(
+                            new OutputStreamWriter(usapSessionSocket.getOutputStream()),
+                            Zygote.SOCKET_BUFFER_SIZE);
+            final DataInputStream usapReader =
+                    new DataInputStream(usapSessionSocket.getInputStream());
+
+            usapWriter.write(msgStr);
+            usapWriter.flush();
+
+            Process.ProcessStartResult result = new Process.ProcessStartResult();
+            result.pid = usapReader.readInt();
+            // USAPs can't be used to spawn processes that need wrappers.
+            result.usingWrapper = false;
+
+            if (result.pid >= 0) {
+                return result;
+            } else {
+                throw new ZygoteStartFailedEx("USAP specialization failed");
+            }
         }
-
-        return result;
     }
 
     /**
@@ -557,7 +547,7 @@
                                                       boolean useUnspecializedAppProcessPool,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
-        ArrayList<String> argsForZygote = new ArrayList<String>();
+        ArrayList<String> argsForZygote = new ArrayList<>();
 
         // --runtime-args, --setuid=, --setgid=,
         // and --setgroups= must go first
@@ -627,17 +617,7 @@
         }
 
         if (packagesForUid != null && packagesForUid.length > 0) {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("--packages-for-uid=");
-
-            // TODO (chriswailes): Replace with String.join
-            for (int i = 0; i < packagesForUid.length; ++i) {
-                if (i != 0) {
-                    sb.append(',');
-                }
-                sb.append(packagesForUid[i]);
-            }
-            argsForZygote.add(sb.toString());
+            argsForZygote.add("--packages-for-uid=" + String.join(",", packagesForUid));
         }
 
         if (sandboxId != null) {
@@ -647,9 +627,7 @@
         argsForZygote.add(processClass);
 
         if (extraArgs != null) {
-            for (String arg : extraArgs) {
-                argsForZygote.add(arg);
-            }
+            Collections.addAll(argsForZygote, extraArgs);
         }
 
         synchronized(mLock) {
@@ -805,10 +783,10 @@
         if (state == null || state.isClosed()) {
             Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
             return false;
-        }
-        if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
+        } else if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
             return true;
         }
+
         try {
             state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
             state.mZygoteOutputWriter.newLine();
@@ -832,17 +810,15 @@
     }
 
     private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
-        if (state == null || state.isClosed()) {
+        if (state == null || state.isClosed() || mHiddenApiAccessLogSampleRate == -1) {
             return;
         }
-        if (mHiddenApiAccessLogSampleRate == -1) {
-            return;
-        }
+
         try {
             state.mZygoteOutputWriter.write(Integer.toString(1));
             state.mZygoteOutputWriter.newLine();
             state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
-                    + Integer.toString(mHiddenApiAccessLogSampleRate));
+                    + mHiddenApiAccessLogSampleRate);
             state.mZygoteOutputWriter.newLine();
             state.mZygoteOutputWriter.flush();
             int status = state.mZygoteInputStream.readInt();
@@ -855,17 +831,15 @@
     }
 
     private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
-        if (state == null || state.isClosed()) {
+        if (state == null || state.isClosed() || mHiddenApiAccessStatslogSampleRate == -1) {
             return;
         }
-        if (mHiddenApiAccessStatslogSampleRate == -1) {
-            return;
-        }
+
         try {
             state.mZygoteOutputWriter.write(Integer.toString(1));
             state.mZygoteOutputWriter.newLine();
             state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
-                    + Integer.toString(mHiddenApiAccessStatslogSampleRate));
+                    + mHiddenApiAccessStatslogSampleRate);
             state.mZygoteOutputWriter.newLine();
             state.mZygoteOutputWriter.flush();
             int status = state.mZygoteInputStream.readInt();
@@ -942,8 +916,8 @@
      * Only the app zygote supports this function.
      * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
      */
-    public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
-                                                                          IOException {
+    public boolean preloadApp(ApplicationInfo appInfo, String abi)
+            throws ZygoteStartFailedEx, IOException {
         synchronized (mLock) {
             ZygoteState state = openZygoteSocketIfNeeded(abi);
             state.mZygoteOutputWriter.write("2");
@@ -971,10 +945,10 @@
      * Instructs the zygote to pre-load the classes and native libraries at the given paths
      * for the specified abi. Not all zygotes support this function.
      */
-    public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
-                                        String cacheKey, String abi) throws ZygoteStartFailedEx,
-                                                                            IOException {
-        synchronized(mLock) {
+    public boolean preloadPackageForAbi(
+            String packagePath, String libsPath, String libFileName, String cacheKey, String abi)
+            throws ZygoteStartFailedEx, IOException {
+        synchronized (mLock) {
             ZygoteState state = openZygoteSocketIfNeeded(abi);
             state.mZygoteOutputWriter.write("5");
             state.mZygoteOutputWriter.newLine();
@@ -1049,8 +1023,7 @@
 
             try {
                 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
-            } catch (InterruptedException ie) {
-            }
+            } catch (InterruptedException ignored) { }
         }
         Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
                 + zygoteSocketAddress.getName());
diff --git a/core/java/android/content/DynamicAndroidClient.java b/core/java/android/os/image/DynamicSystemClient.java
similarity index 64%
rename from core/java/android/content/DynamicAndroidClient.java
rename to core/java/android/os/image/DynamicSystemClient.java
index 571cba4..33a6ee8 100644
--- a/core/java/android/content/DynamicAndroidClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -13,12 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.content;
+package android.os.image;
 
+import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -34,12 +40,28 @@
 import java.util.concurrent.Executor;
 
 /**
- * This class contains methods and constants used to start DynamicAndroid
- * installation, and a listener for progress update.
+ * <p>This class contains methods and constants used to start a {@code DynamicSystem} installation,
+ * and a listener for status updates.</p>
+ *
+ * <p>{@code DynamicSystem} allows user to run certified system images in a non destructive manner
+ * without needing to prior OEM unlock. While running in {@code DynamicSystem}, persitent storage
+ * for factory reset protection (FRP) remains unchanged. The new system is installed in a
+ * temporarily allocated partition. After the installation is completed, the device will be running
+ * in the new system on next reboot. Then, when the user reboots the device again, it will leave
+ * {@code DynamicSystem} and go back into the original system. Since the userdata for
+ * {@code DynamicSystem} is also newly created during the installation, running in
+ * {@code DynamicSystem} doesn't change user's app data.</p>
+ *
+ * <p>With {@link #setOnStatusChangedListener}, API users can register an
+ * {@link #OnStatusChangedListener} and get status updates and cause when the installation is
+ * started, stopped, or cancelled. It also sends progress updates during the installation. With
+ * {@link #start}, API users can start an installation with the {@link Uri} to a gzipped system
+ * image. The {@link Uri} can be a web URL or a content Uri to a local path.</p>
+ *
  * @hide
  */
 @SystemApi
-public class DynamicAndroidClient {
+public class DynamicSystemClient {
     /** @hide */
     @IntDef(prefix = { "STATUS_" }, value = {
             STATUS_UNKNOWN,
@@ -64,23 +86,23 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface StatusChangedCause {}
 
-    private static final String TAG = "DynAndroidClient";
+    private static final String TAG = "DynSystemClient";
 
     private static final long DEFAULT_USERDATA_SIZE = (10L << 30);
 
 
-    /** Listener for installation status update. */
+    /** Listener for installation status updates. */
     public interface OnStatusChangedListener {
         /**
          * This callback is called when installation status is changed, and when the
-         * client is {@link #bind} to DynamicAndroid installation service.
+         * client is {@link #bind} to {@code DynamicSystem} installation service.
          *
-         * @param status status code, also defined in {@code DynamicAndroidClient}.
-         * @param cause cause code, also defined in {@code DynamicAndroidClient}.
+         * @param status status code, also defined in {@code DynamicSystemClient}.
+         * @param cause cause code, also defined in {@code DynamicSystemClient}.
          * @param progress number of bytes installed.
          */
         void onStatusChanged(@InstallationStatus int status, @StatusChangedCause int cause,
-                long progress);
+                @BytesLong long progress);
     }
 
     /*
@@ -98,7 +120,7 @@
     /** Installation is finished but the user has not launched it. */
     public static final int STATUS_READY = 3;
 
-    /** Device is running in Dynamic Android. */
+    /** Device is running in {@code DynamicSystem}. */
     public static final int STATUS_IN_USE = 4;
 
     /*
@@ -113,7 +135,7 @@
     /** Status changed because installation is cancelled. */
     public static final int CAUSE_INSTALL_CANCELLED = 2;
 
-    /** Installation failed due to IOException. */
+    /** Installation failed due to {@code IOException}. */
     public static final int CAUSE_ERROR_IO = 3;
 
     /** Installation failed because the image URL source is not supported. */
@@ -141,7 +163,7 @@
     public static final int MSG_UNREGISTER_LISTENER = 2;
 
     /**
-     * Message for status update.
+     * Message for status updates.
      * @hide
      */
     public static final int MSG_POST_STATUS = 3;
@@ -150,7 +172,7 @@
      * Messages keys
      */
     /**
-     * Message key, for progress update.
+     * Message key, for progress updates.
      * @hide
      */
     public static final String KEY_INSTALLED_SIZE = "KEY_INSTALLED_SIZE";
@@ -163,14 +185,14 @@
      * @hide
      */
     public static final String ACTION_START_INSTALL =
-            "android.content.action.START_INSTALL";
+            "android.os.image.action.START_INSTALL";
 
     /**
-     * Intent action: notify user if we are currently running in Dynamic Android.
+     * Intent action: notify user if we are currently running in {@code DynamicSystem}.
      * @hide
      */
     public static final String ACTION_NOTIFY_IF_IN_USE =
-            "android.content.action.NOTIFY_IF_IN_USE";
+            "android.os.image.action.NOTIFY_IF_IN_USE";
 
     /*
      * Intent Keys
@@ -195,16 +217,16 @@
 
 
     private static class IncomingHandler extends Handler {
-        private final WeakReference<DynamicAndroidClient> mWeakClient;
+        private final WeakReference<DynamicSystemClient> mWeakClient;
 
-        IncomingHandler(DynamicAndroidClient service) {
+        IncomingHandler(DynamicSystemClient service) {
             super(Looper.getMainLooper());
             mWeakClient = new WeakReference<>(service);
         }
 
         @Override
         public void handleMessage(Message msg) {
-            DynamicAndroidClient service = mWeakClient.get();
+            DynamicSystemClient service = mWeakClient.get();
 
             if (service != null) {
                 service.handleMessage(msg);
@@ -212,9 +234,9 @@
         }
     }
 
-    private class DynAndroidServiceConnection implements ServiceConnection {
+    private class DynSystemServiceConnection implements ServiceConnection {
         public void onServiceConnected(ComponentName className, IBinder service) {
-            Slog.v(TAG, "DynAndroidService connected");
+            Slog.v(TAG, "DynSystemService connected");
 
             mService = new Messenger(service);
 
@@ -232,13 +254,13 @@
         }
 
         public void onServiceDisconnected(ComponentName className) {
-            Slog.v(TAG, "DynAndroidService disconnected");
+            Slog.v(TAG, "DynSystemService disconnected");
             mService = null;
         }
     }
 
     private final Context mContext;
-    private final DynAndroidServiceConnection mConnection;
+    private final DynSystemServiceConnection mConnection;
     private final Messenger mMessenger;
 
     private boolean mBound;
@@ -247,12 +269,16 @@
     private Messenger mService;
 
     /**
+     * Create a new {@code DynamicSystem} client.
+     *
+     * @param context a {@link Context} will be used to bind the installation service.
+     *
      * @hide
      */
     @SystemApi
-    public DynamicAndroidClient(@NonNull Context context) {
+    public DynamicSystemClient(@NonNull Context context) {
         mContext = context;
-        mConnection = new DynAndroidServiceConnection();
+        mConnection = new DynSystemServiceConnection();
         mMessenger = new Messenger(new IncomingHandler(this));
     }
 
@@ -261,8 +287,8 @@
      * the executor.
      */
     public void setOnStatusChangedListener(
-            @NonNull OnStatusChangedListener listener,
-            @NonNull @CallbackExecutor Executor executor) {
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnStatusChangedListener listener) {
         mListener = listener;
         mExecutor = executor;
     }
@@ -278,12 +304,15 @@
     }
 
     /**
-     * Bind to DynamicAndroidInstallationService.
+     * Bind to {@code DynamicSystem} installation service. Binding to the installation service
+     * allows it to send status updates to {@link #OnStatusChangedListener}. It is recommanded
+     * to bind before calling {@link #start} and get status updates.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public void bind() {
         Intent intent = new Intent();
-        intent.setClassName("com.android.dynandroid",
-                "com.android.dynandroid.DynamicAndroidInstallationService");
+        intent.setClassName("com.android.dynsystem",
+                "com.android.dynsystem.DynamicSystemInstallationService");
 
         mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 
@@ -291,8 +320,10 @@
     }
 
     /**
-     * Unbind from DynamicAndroidInstallationService.
+     * Unbind from {@code DynamicSystem} installation service. Unbinding from the installation
+     * service stops it from sending following status updates.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public void unbind() {
         if (!mBound) {
             return;
@@ -315,27 +346,40 @@
     }
 
     /**
-     * Start installing DynamicAndroid from URL with default userdata size.
+     * Start installing {@code DynamicSystem} from URL with default userdata size.
+     *
+     * Calling this function will first start an Activity to confirm device credential, using
+     * {@link KeyguardManager}. If it's confirmed, the installation service will be started.
+     *
+     * This function doesn't require prior calling {@link #bind}.
      *
      * @param systemUrl A network URL or a file URL to system image.
      * @param systemSize size of system image.
      */
-    public void start(String systemUrl, long systemSize) {
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+    public void start(@NonNull String systemUrl, @BytesLong long systemSize) {
         start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
     }
 
     /**
-     * Start installing DynamicAndroid from URL.
+     * Start installing {@code DynamicSystem} from URL.
+     *
+     * Calling this function will first start an Activity to confirm device credential, using
+     * {@link KeyguardManager}. If it's confirmed, the installation service will be started.
+     *
+     * This function doesn't require prior calling {@link #bind}.
      *
      * @param systemUrl A network URL or a file URL to system image.
      * @param systemSize size of system image.
      * @param userdataSize bytes reserved for userdata.
      */
-    public void start(String systemUrl, long systemSize, long userdataSize) {
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+    public void start(@NonNull String systemUrl, @BytesLong long systemSize,
+            @BytesLong long userdataSize) {
         Intent intent = new Intent();
 
-        intent.setClassName("com.android.dynandroid",
-                "com.android.dynandroid.VerificationActivity");
+        intent.setClassName("com.android.dynsystem",
+                "com.android.dynsystem.VerificationActivity");
 
         intent.setAction(ACTION_START_INSTALL);
 
diff --git a/core/java/android/os/DynamicAndroidManager.java b/core/java/android/os/image/DynamicSystemManager.java
similarity index 81%
rename from core/java/android/os/DynamicAndroidManager.java
rename to core/java/android/os/image/DynamicSystemManager.java
index 5238896..0458c2a 100644
--- a/core/java/android/os/DynamicAndroidManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -14,50 +14,51 @@
  * limitations under the License.
  */
 
-package android.os;
+package android.os.image;
 
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.gsi.GsiProgress;
+import android.os.RemoteException;
 
 /**
- * The DynamicAndroidManager offers a mechanism to use a new Android image temporarily. After the
+ * The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the
  * installation, the device can reboot into this image with a new created /data. This image will
  * last until the next reboot and then the device will go back to the original image. However the
  * installed image and the new created /data are not deleted but disabled. Thus the application can
  * either re-enable the installed image by calling {@link #toggle} or use the {@link #remove} to
  * delete it completely. In other words, there are three device states: no installation, installed
- * and running. The procedure to install a DynamicAndroid starts with a {@link #startInstallation},
+ * and running. The procedure to install a DynamicSystem starts with a {@link #startInstallation},
  * followed by a series of {@link #write} and ends with a {@link commit}. Once the installation is
  * complete, the device state changes from no installation to the installed state and a followed
- * reboot will change its state to running. Note one instance of dynamic android can exist on a
- * given device thus the {@link #startInstallation} will fail if the device is currently running a
- * DynamicAndroid.
+ * reboot will change its state to running. Note one instance of DynamicSystem can exist on a given
+ * device thus the {@link #startInstallation} will fail if the device is currently running a
+ * DynamicSystem.
  *
  * @hide
  */
-@SystemService(Context.DYNAMIC_ANDROID_SERVICE)
-public class DynamicAndroidManager {
-    private static final String TAG = "DynamicAndroidManager";
+@SystemService(Context.DYNAMIC_SYSTEM_SERVICE)
+public class DynamicSystemManager {
+    private static final String TAG = "DynamicSystemManager";
 
-    private final IDynamicAndroidService mService;
+    private final IDynamicSystemService mService;
 
     /** {@hide} */
-    public DynamicAndroidManager(IDynamicAndroidService service) {
+    public DynamicSystemManager(IDynamicSystemService service) {
         mService = service;
     }
 
-    /** The DynamicAndroidManager.Session represents a started session for the installation. */
+    /** The DynamicSystemManager.Session represents a started session for the installation. */
     public class Session {
         private Session() {}
         /**
-         * Write a chunk of the DynamicAndroid system image
+         * Write a chunk of the DynamicSystem system image
          *
          * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
          *     error.
          */
-        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
         public boolean write(byte[] buf) {
             try {
                 return mService.write(buf);
@@ -72,7 +73,7 @@
          * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
          *     error.
          */
-        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
         public boolean commit() {
             try {
                 return mService.commit();
@@ -82,16 +83,16 @@
         }
     }
     /**
-     * Start DynamicAndroid installation. This call may take an unbounded amount of time. The caller
+     * Start DynamicSystem installation. This call may take an unbounded amount of time. The caller
      * may use another thread to call the getStartProgress() to get the progress.
      *
      * @param systemSize system size in bytes
      * @param userdataSize userdata size in bytes
      * @return {@code true} if the call succeeds. {@code false} either the device does not contain
-     *     enough space or a DynamicAndroid is currently in use where the {@link #isInUse} would be
+     *     enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be
      *     true.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public Session startInstallation(long systemSize, long userdataSize) {
         try {
             if (mService.startInstallation(systemSize, userdataSize)) {
@@ -112,7 +113,7 @@
      *     status field can be IGsiService.STATUS_NO_OPERATION, IGsiService.STATUS_WORKING or
      *     IGsiService.STATUS_COMPLETE.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public GsiProgress getInstallationProgress() {
         try {
             return mService.getInstallationProgress();
@@ -129,7 +130,7 @@
      * @return {@code true} if the call succeeds. {@code false} if there is no installation
      *     currently.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public boolean abort() {
         try {
             return mService.abort();
@@ -138,8 +139,8 @@
         }
     }
 
-    /** @return {@code true} if the device is running a dynamic android */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    /** @return {@code true} if the device is running a dynamic system */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public boolean isInUse() {
         try {
             return mService.isInUse();
@@ -148,8 +149,8 @@
         }
     }
 
-    /** @return {@code true} if the device has a dynamic android installed */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    /** @return {@code true} if the device has a dynamic system installed */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public boolean isInstalled() {
         try {
             return mService.isInstalled();
@@ -159,11 +160,11 @@
     }
 
     /**
-     * Remove DynamicAndroid installation if present
+     * Remove DynamicSystem installation if present
      *
      * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public boolean remove() {
         try {
             return mService.remove();
@@ -173,11 +174,11 @@
     }
 
     /**
-     * Enable DynamicAndroid when it's not enabled, otherwise, disable it.
+     * Enable DynamicSystem when it's not enabled, otherwise, disable it.
      *
      * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
     public boolean toggle() {
         try {
             return mService.toggle();
diff --git a/core/java/android/os/IDynamicAndroidService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
similarity index 83%
rename from core/java/android/os/IDynamicAndroidService.aidl
rename to core/java/android/os/image/IDynamicSystemService.aidl
index 0b28799..15f5b68 100644
--- a/core/java/android/os/IDynamicAndroidService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.os;
+package android.os.image;
 
 import android.gsi.GsiProgress;
 
 /** {@hide} */
-interface IDynamicAndroidService
+interface IDynamicSystemService
 {
     /**
-     * Start DynamicAndroid installation. This call may take 60~90 seconds. The caller
+     * Start DynamicSystem installation. This call may take 60~90 seconds. The caller
      * may use another thread to call the getStartProgress() to get the progress.
      *
      * @param systemSize system size in bytes
@@ -53,26 +53,26 @@
     boolean isInUse();
 
     /**
-     * @return true if the device has an DynamicAndroid image installed
+     * @return true if the device has an DynamicSystem image installed
      */
     boolean isInstalled();
 
     /**
-     * Remove DynamicAndroid installation if present
+     * Remove DynamicSystem installation if present
      *
      * @return true if the call succeeds
      */
     boolean remove();
 
     /**
-     * Enable DynamicAndroid when it's not enabled, otherwise, disable it.
+     * Enable DynamicSystem when it's not enabled, otherwise, disable it.
      *
      * @return true if the call succeeds
      */
     boolean toggle();
 
     /**
-     * Write a chunk of the DynamicAndroid system image
+     * Write a chunk of the DynamicSystem system image
      *
      * @return true if the call succeeds
      */
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 1486333..368ba3c 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -873,7 +873,7 @@
      */
     public interface MediaColumns extends BaseColumns {
         /**
-         * Path to the media item on disk.
+         * Absolute filesystem path to the media item on disk.
          * <p>
          * Note that apps may not have filesystem permissions to directly access
          * this path. Instead of trying to open this path directly, apps should
@@ -920,6 +920,10 @@
 
         /**
          * The display name of the media item.
+         * <p>
+         * For example, an item stored at
+         * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
+         * display name of {@code IMG1024.JPG}.
          */
         @Column(Cursor.FIELD_TYPE_STRING)
         public static final String DISPLAY_NAME = "_display_name";
@@ -985,7 +989,8 @@
 
         /**
          * Flag indicating if a media item is pending, and still being inserted
-         * by its owner.
+         * by its owner. While this flag is set, only the owner of the item can
+         * open the underlying file; requests from other apps will be rejected.
          *
          * @see MediaStore#setIncludePending(Uri)
          */
@@ -1033,17 +1038,53 @@
         public static final String OWNER_PACKAGE_NAME = "owner_package_name";
 
         /**
-         * The primary directory name this media exists under. The value may be
-         * {@code NULL} if the media doesn't have a primary directory name.
+         * Relative path of this media item within the storage device where it
+         * is persisted. For example, an item stored at
+         * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
+         * path of {@code DCIM/Vacation}.
+         * <p>
+         * This value should only be used for organizational purposes, and you
+         * should not attempt to construct or access a raw filesystem path using
+         * this value. If you need to open a media item, use an API like
+         * {@link ContentResolver#openFileDescriptor(Uri, String)}.
+         * <p>
+         * When this value is set to {@code NULL} during an
+         * {@link ContentResolver#insert} operation, the newly created item will
+         * be placed in a relevant default location based on the type of media
+         * being inserted. For example, a {@code image/jpeg} item will be placed
+         * under {@link Environment#DIRECTORY_PICTURES}.
+         * <p>
+         * You can modify this column during an {@link ContentResolver#update}
+         * call, which will move the underlying file on disk.
+         * <p>
+         * In both cases above, content must be placed under a top-level
+         * directory that is relevant to the media type. For example, attempting
+         * to place a {@code audio/mpeg} file under
+         * {@link Environment#DIRECTORY_PICTURES} will be rejected.
          */
         @Column(Cursor.FIELD_TYPE_STRING)
+        public static final String RELATIVE_PATH = "relative_path";
+
+        /**
+         * The primary directory name this media exists under. The value may be
+         * {@code NULL} if the media doesn't have a primary directory name.
+         *
+         * @removed
+         * @deprecated Replaced by {@link #RELATIVE_PATH}.
+         */
+        @Column(Cursor.FIELD_TYPE_STRING)
+        @Deprecated
         public static final String PRIMARY_DIRECTORY = "primary_directory";
 
         /**
          * The secondary directory name this media exists under. The value may
          * be {@code NULL} if the media doesn't have a secondary directory name.
+         *
+         * @removed
+         * @deprecated Replaced by {@link #RELATIVE_PATH}.
          */
         @Column(Cursor.FIELD_TYPE_STRING)
+        @Deprecated
         public static final String SECONDARY_DIRECTORY = "secondary_directory";
 
         /**
@@ -3344,6 +3385,10 @@
      * substantial changes, and that data should be rescanned.
      * <p>
      * No other assumptions should be made about the meaning of the version.
+     *
+     * @param volumeName specific volume to obtain an opaque version string for.
+     *            Must be one of the values returned from
+     *            {@link #getAllVolumeNames(Context)}.
      */
     public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) {
         final ContentResolver resolver = context.getContentResolver();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7d66b90..6dd7ecc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -73,6 +73,7 @@
 import android.os.DropBoxManager;
 import android.os.IBinder;
 import android.os.LocaleList;
+import android.os.PowerManager.AutoPowerSaveModeTriggers;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -1261,6 +1262,25 @@
             = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
 
     /**
+     * Activity Action: Show do not disturb setting page for app.
+     * <p>
+     * Users can grant and deny access to Do Not Disturb configuration for an app from here.
+     * See {@link android.app.NotificationManager#isNotificationPolicyAccessGranted()} for more
+     * details.
+     * <p>
+     * Input: Intent's data URI set with an application name, using the
+     * "package" schema (like "package:com.my.app").
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS =
+            "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
+
+    /**
      * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -12580,12 +12600,11 @@
         /**
          * Battery level [1-100] at which low power mode automatically turns on.
          * If 0, it will not automatically turn on. For Q and newer, it will only automatically
-         * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE}
+         * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVE_MODE}
          * setting is also set to
-         * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
-         *
-         * @see #AUTOMATIC_POWER_SAVER_MODE
-         * @see android.os.PowerManager#getPowerSaveMode()
+         * {@link android.os.PowerManager.AutoPowerSaveMode#POWER_SAVE_MODE_TRIGGER_PERCENTAGE}.
+         * @see #AUTOMATIC_POWER_SAVE_MODE
+         * @see android.os.PowerManager#getPowerSaveModeTrigger()
          * @hide
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
@@ -12595,22 +12614,22 @@
 
         /**
          * Whether battery saver is currently set to trigger based on percentage, dynamic power
-         * savings trigger, or none. See {@link android.os.PowerManager.AutoPowerSaverMode} for
+         * savings trigger, or none. See {@link AutoPowerSaveModeTriggers} for
          * accepted values.
          *
          *  @hide
          */
         @TestApi
-        public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+        public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
 
-        private static final Validator AUTOMATIC_POWER_SAVER_MODE_VALIDATOR =
+        private static final Validator AUTOMATIC_POWER_SAVE_MODE_VALIDATOR =
                 new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
 
         /**
          * The setting that backs the disable threshold for the setPowerSavingsWarning api in
          * PowerManager
          *
-         * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
+         * @see android.os.PowerManager#setDynamicPowerSaveHint(boolean, int)
          * @hide
          */
         @TestApi
@@ -12620,9 +12639,9 @@
                 new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
 
         /**
-         * The setting which backs the setDynamicPowerSavings api in PowerManager.
+         * The setting which backs the setDynamicPowerSaveHint api in PowerManager.
          *
-         * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
+         * @see android.os.PowerManager#setDynamicPowerSaveHint(boolean, int)
          * @hide
          */
         @TestApi
@@ -13611,7 +13630,7 @@
             VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
             VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
                     LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
-            VALIDATORS.put(AUTOMATIC_POWER_SAVER_MODE, AUTOMATIC_POWER_SAVER_MODE_VALIDATOR);
+            VALIDATORS.put(AUTOMATIC_POWER_SAVE_MODE, AUTOMATIC_POWER_SAVE_MODE_VALIDATOR);
             VALIDATORS.put(DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                     DYNAMIC_POWER_SAVINGS_VALIDATOR);
             VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
diff --git a/core/java/android/service/appprediction/AppPredictionService.java b/core/java/android/service/appprediction/AppPredictionService.java
index ff13e03..c1323bc 100644
--- a/core/java/android/service/appprediction/AppPredictionService.java
+++ b/core/java/android/service/appprediction/AppPredictionService.java
@@ -86,11 +86,12 @@
         }
 
         @Override
-        public void notifyLocationShown(AppPredictionSessionId sessionId, String launchLocation,
-                ParceledListSlice targetIds) {
+        public void notifyLaunchLocationShown(AppPredictionSessionId sessionId,
+                String launchLocation, ParceledListSlice targetIds) {
             mHandler.sendMessage(
-                    obtainMessage(AppPredictionService::onLocationShown, AppPredictionService.this,
-                            sessionId, launchLocation, targetIds.getList()));
+                    obtainMessage(AppPredictionService::onLaunchLocationShown,
+                            AppPredictionService.this, sessionId, launchLocation,
+                            targetIds.getList()));
         }
 
         @Override
@@ -158,7 +159,7 @@
      * Called by a client app to indication a particular location has been shown to the user.
      */
     @MainThread
-    public abstract void onLocationShown(@NonNull AppPredictionSessionId sessionId,
+    public abstract void onLaunchLocationShown(@NonNull AppPredictionSessionId sessionId,
             @NonNull String launchLocation, @NonNull List<AppTargetId> targetIds);
 
     private void doCreatePredictionSession(@NonNull AppPredictionContext context,
diff --git a/core/java/android/service/appprediction/IPredictionService.aidl b/core/java/android/service/appprediction/IPredictionService.aidl
index 3a6d166..0f3df85 100644
--- a/core/java/android/service/appprediction/IPredictionService.aidl
+++ b/core/java/android/service/appprediction/IPredictionService.aidl
@@ -35,7 +35,7 @@
 
     void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
 
-    void notifyLocationShown(in AppPredictionSessionId sessionId,  in String launchLocation,
+    void notifyLaunchLocationShown(in AppPredictionSessionId sessionId,  in String launchLocation,
             in ParceledListSlice targetIds);
 
     void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
index 32f4ea9..84f440f 100644
--- a/core/java/android/service/attention/AttentionService.java
+++ b/core/java/android/service/attention/AttentionService.java
@@ -21,11 +21,13 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.attention.AttentionManagerInternal;
 import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
 
 import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -65,14 +67,20 @@
     /** Attention is present. */
     public static final int ATTENTION_SUCCESS_PRESENT = 1;
 
+    /** Unknown reasons for failing to determine the attention. */
+    public static final int ATTENTION_FAILURE_UNKNOWN = 2;
+
+    /** Request has been cancelled. */
+    public static final int ATTENTION_FAILURE_CANCELLED = 3;
+
     /** Preempted by other client. */
-    public static final int ATTENTION_FAILURE_PREEMPTED = 2;
+    public static final int ATTENTION_FAILURE_PREEMPTED = 4;
 
     /** Request timed out. */
-    public static final int ATTENTION_FAILURE_TIMED_OUT = 3;
+    public static final int ATTENTION_FAILURE_TIMED_OUT = 5;
 
-    /** Unknown reasons for failing to determine the attention. */
-    public static final int ATTENTION_FAILURE_UNKNOWN = 4;
+    /** Camera permission is not granted. */
+    public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6;
 
     /**
      * Result codes for when attention check was successful.
@@ -90,8 +98,9 @@
      *
      * @hide
      */
-    @IntDef(prefix = {"ATTENTION_FAILURE_"}, value = {ATTENTION_FAILURE_PREEMPTED,
-            ATTENTION_FAILURE_TIMED_OUT, ATTENTION_FAILURE_UNKNOWN})
+    @IntDef(prefix = {"ATTENTION_FAILURE_"}, value = {ATTENTION_FAILURE_UNKNOWN,
+            ATTENTION_FAILURE_CANCELLED, ATTENTION_FAILURE_PREEMPTED, ATTENTION_FAILURE_TIMED_OUT,
+            ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AttentionFailureCodes {
     }
@@ -122,6 +131,19 @@
     }
 
     /**
+     * Disables the dependants.
+     *
+     * Example: called if the service does not have sufficient permissions to perform the task.
+     */
+    public final void disableSelf() {
+        AttentionManagerInternal attentionManager = LocalServices.getService(
+                AttentionManagerInternal.class);
+        if (attentionManager != null) {
+            attentionManager.disableSelf();
+        }
+    }
+
+    /**
      * Checks the user attention and calls into the provided callback.
      *
      * @param requestCode an identifier that could be used to cancel the request
@@ -132,7 +154,6 @@
     /** Cancels the attention check for a given request code. */
     public abstract void onCancelAttentionCheck(int requestCode);
 
-
     /** Callbacks for AttentionService results. */
     public static final class AttentionCallback {
         private final IAttentionCallback mCallback;
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index df11397..fb07aba 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -298,12 +298,12 @@
     /**
      * Disables the Content Capture service for the given user.
      */
-    public final void disableContentCaptureServices() {
-        if (sDebug) Log.d(TAG, "disableContentCaptureServices()");
+    public final void disableSelf() {
+        if (sDebug) Log.d(TAG, "disableSelf()");
 
         final IContentCaptureServiceCallback callback = mCallback;
         if (callback == null) {
-            Log.w(TAG, "disableContentCaptureServices(): no server callback");
+            Log.w(TAG, "disableSelf(): no server callback");
             return;
         }
         try {
@@ -367,7 +367,6 @@
             stateFlags = initialState;
         } else {
             stateFlags |= ContentCaptureSession.STATE_DISABLED;
-
         }
         setClientState(clientReceiver, stateFlags, mClientInterface.asBinder());
     }
diff --git a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
index 6ecd82f..fb60619 100644
--- a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
+++ b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
@@ -139,6 +139,7 @@
         mSettingsActivity = settingsActivity;
     }
 
+    @NonNull
     public ServiceInfo getServiceInfo() {
         return mServiceInfo;
     }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c042a8c..e1762df 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -320,7 +320,7 @@
             public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                     Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                     MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
-                    boolean alwaysConsumeNavBar, int displayId,
+                    boolean alwaysConsumeSystemBars, int displayId,
                     DisplayCutout.ParcelableWrapper displayCutout) {
                 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0, outsets);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index de10ffb..da6ef4c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -52,14 +52,14 @@
         DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_mainline_module", "true");
-        DEFAULT_FLAGS.put("settings_dynamic_android", "false");
+        DEFAULT_FLAGS.put("settings_dynamic_system", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
-        DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "false");
+        DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true");
         DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
     }
 
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index bf46e95..30d3d7d 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -22,6 +22,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.os.IStatsManager;
@@ -199,6 +200,16 @@
         }
     }
 
+    /**
+     * Write an event to stats log using the raw format.
+     *
+     * @param buffer    The encoded buffer of data to write..
+     * @param size      The number of bytes from the buffer to write.
+     * @hide
+     */
+    @SystemApi
+    public static native void writeRaw(@NonNull byte[] buffer, int size);
+
     private static void enforceDumpCallingPermission(Context context) {
         context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
     }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index c06a1fe..699e795 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -53,7 +53,7 @@
     void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
             in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
             in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
-            boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
             in DisplayCutout.ParcelableWrapper displayCutout);
 
     /**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b91b93f..6c37319 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -304,6 +304,16 @@
     oneway void statusBarVisibilityChanged(int displayId, int visibility);
 
     /**
+    * When set to {@code true} the system bars will always be shown. This is true even if an app
+    * requests to be fullscreen by setting the system ui visibility flags. The
+    * functionality was added for the automotive case as a way to guarantee required content stays
+    * on screen at all times.
+    *
+    * @hide
+    */
+    oneway void setForceShowSystemBars(boolean show);
+
+    /**
      * Called by System UI to notify of changes to the visibility of Recents.
      */
     oneway void setRecentsVisibility(boolean visible);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 08f2e8d..bf16e3d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -134,7 +134,7 @@
             }
 
             WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
-                    mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
+                    mLastInsets.shouldAlwaysConsumeSystemBars(), mLastInsets.getDisplayCutout(),
                     mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode,
                     null /* typeSideMap */);
             mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
@@ -177,12 +177,12 @@
      */
     @VisibleForTesting
     public WindowInsets calculateInsets(boolean isScreenRound,
-            boolean alwaysConsumeNavBar, DisplayCutout cutout, Rect legacyContentInsets,
+            boolean alwaysConsumeSystemBars, DisplayCutout cutout, Rect legacyContentInsets,
             Rect legacyStableInsets, int legacySoftInputMode) {
         mLastLegacyContentInsets.set(legacyContentInsets);
         mLastLegacyStableInsets.set(legacyStableInsets);
         mLastLegacySoftInputMode = legacySoftInputMode;
-        mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout,
+        mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeSystemBars, cutout,
                 legacyContentInsets, legacyStableInsets, legacySoftInputMode,
                 null /* typeSideMap */);
         return mLastInsets;
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6129b38..13b0cc0 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -17,9 +17,6 @@
 package android.view;
 
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
-import static android.view.WindowInsets.Type.IME;
 import static android.view.WindowInsets.Type.SIZE;
 import static android.view.WindowInsets.Type.indexOf;
 
@@ -31,7 +28,6 @@
 import android.os.Parcelable;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetType;
@@ -40,7 +36,6 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -130,7 +125,7 @@
      * @return The calculated insets.
      */
     public WindowInsets calculateInsets(Rect frame, boolean isScreenRound,
-            boolean alwaysConsumeNavBar, DisplayCutout cutout,
+            boolean alwaysConsumeSystemBars, DisplayCutout cutout,
             @Nullable Rect legacyContentInsets, @Nullable Rect legacyStableInsets,
             int legacySoftInputMode, @Nullable @InsetSide SparseIntArray typeSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
@@ -180,7 +175,7 @@
             }
         }
         return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
-                alwaysConsumeNavBar, cutout);
+                alwaysConsumeSystemBars, cutout);
     }
 
     private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index cd075bf..0043d32 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -88,10 +88,10 @@
     private static native void nativeDestroy(long nativeObject);
     private static native void nativeDisconnect(long nativeObject);
 
-    private static native GraphicBuffer nativeScreenshot(IBinder displayToken,
+    private static native ScreenshotGraphicBuffer nativeScreenshot(IBinder displayToken,
             Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
             boolean captureSecureLayers);
-    private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
+    private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
             Rect sourceCrop, float frameScale);
 
     private static native long nativeCreateTransaction();
@@ -431,7 +431,52 @@
     public static final int METADATA_TASK_ID = 3;
 
     /**
+     * A wrapper around GraphicBuffer that contains extra information about how to
+     * interpret the screenshot GraphicBuffer.
+     * @hide
+     */
+    public static class ScreenshotGraphicBuffer {
+        private final GraphicBuffer mGraphicBuffer;
+        private final ColorSpace mColorSpace;
+
+        public ScreenshotGraphicBuffer(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+            mGraphicBuffer = graphicBuffer;
+            mColorSpace = colorSpace;
+        }
+
+       /**
+        * Create ScreenshotGraphicBuffer from existing native GraphicBuffer object.
+        * @param width The width in pixels of the buffer
+        * @param height The height in pixels of the buffer
+        * @param format The format of each pixel as specified in {@link PixelFormat}
+        * @param usage Hint indicating how the buffer will be used
+        * @param unwrappedNativeObject The native object of GraphicBuffer
+        * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+        */
+        private static ScreenshotGraphicBuffer createFromNative(int width, int height, int format,
+                int usage, long unwrappedNativeObject, int namedColorSpace) {
+            GraphicBuffer graphicBuffer = GraphicBuffer.createFromExisting(width, height, format,
+                    usage, unwrappedNativeObject);
+            ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+            return new ScreenshotGraphicBuffer(graphicBuffer, colorSpace);
+        }
+
+        public ColorSpace getColorSpace() {
+            return mColorSpace;
+        }
+
+        public GraphicBuffer getGraphicBuffer() {
+            return mGraphicBuffer;
+        }
+    }
+
+    /**
      * Builder class for {@link SurfaceControl} objects.
+     *
+     * By default the surface will be hidden, and have "unset" bounds, meaning it can
+     * be as large as the bounds of its parent if a buffer or child so requires.
+     *
+     * It is necessary to set at least a name via {@link Builder#setName}
      */
     public static class Builder {
         private SurfaceSession mSession;
@@ -466,11 +511,11 @@
         @NonNull
         public SurfaceControl build() {
             if (mWidth < 0 || mHeight < 0) {
-                throw new IllegalArgumentException(
+                throw new IllegalStateException(
                         "width and height must be positive or unset");
             }
             if ((mWidth > 0 || mHeight > 0) && (isColorLayerSet() || isContainerLayerSet())) {
-                throw new IllegalArgumentException(
+                throw new IllegalStateException(
                         "Only buffer layers can set a valid buffer size.");
             }
             return new SurfaceControl(
@@ -860,7 +905,9 @@
      * Release the local reference to the server-side surface. The surface
      * may continue to exist on-screen as long as its parent continues
      * to exist. To explicitly remove a surface from the screen use
-     * {@link Transaction#reparent} with a null-parent.
+     * {@link Transaction#reparent} with a null-parent. After release,
+     * {@link #isValid} will return false and other methods will throw
+     * an exception.
      *
      * Always call release() when you're done with a SurfaceControl.
      */
@@ -902,7 +949,8 @@
 
     /**
      * Check whether this instance points to a valid layer with the system-compositor. For
-     * example this may be false if construction failed, or the layer was released.
+     * example this may be false if construction failed, or the layer was released
+     * ({@link #release}).
      *
      * @return Whether this SurfaceControl is valid.
      */
@@ -1815,10 +1863,10 @@
             throw new IllegalArgumentException("consumer must not be null");
         }
 
-        final GraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width, height,
-                useIdentityTransform, rotation);
+        final ScreenshotGraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width,
+                height, useIdentityTransform, rotation);
         try {
-            consumer.attachAndQueueBuffer(buffer);
+            consumer.attachAndQueueBuffer(buffer.getGraphicBuffer());
         } catch (RuntimeException e) {
             Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
         }
@@ -1861,17 +1909,16 @@
         }
 
         SurfaceControl.rotateCropForSF(sourceCrop, rotation);
-        final GraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, height,
-                useIdentityTransform, rotation);
+        final ScreenshotGraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width,
+                height, useIdentityTransform, rotation);
 
         if (buffer == null) {
             Log.w(TAG, "Failed to take screenshot");
             return null;
         }
-        // TODO(b/116112787) Now that hardware bitmap creation can take color space, we
-        // should continue to fix screenshot.
-        return Bitmap.wrapHardwareBuffer(HardwareBuffer.createFromGraphicBuffer(buffer),
-                ColorSpace.get(ColorSpace.Named.SRGB));
+        return Bitmap.wrapHardwareBuffer(
+                HardwareBuffer.createFromGraphicBuffer(buffer.getGraphicBuffer()),
+                buffer.getColorSpace());
     }
 
     /**
@@ -1897,8 +1944,8 @@
      * @return Returns a GraphicBuffer that contains the captured content.
      * @hide
      */
-    public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
-            int height, boolean useIdentityTransform, int rotation) {
+    public static ScreenshotGraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop,
+            int width, int height, boolean useIdentityTransform, int rotation) {
         if (display == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
@@ -1917,7 +1964,7 @@
      *
      * @hide
      */
-    public static GraphicBuffer screenshotToBufferWithSecureLayersUnsafe(IBinder display,
+    public static ScreenshotGraphicBuffer screenshotToBufferWithSecureLayersUnsafe(IBinder display,
             Rect sourceCrop, int width, int height, boolean useIdentityTransform,
             int rotation) {
         if (display == null) {
@@ -1951,7 +1998,7 @@
      * @return Returns a GraphicBuffer that contains the layer capture.
      * @hide
      */
-    public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
+    public static ScreenshotGraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
             float frameScale) {
         return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
     }
@@ -2042,8 +2089,7 @@
         }
 
         /**
-         * Close the transaction, if the transaction was not already applied this will cancel the
-         * transaction.
+         * Release the native transaction object, without applying it.
          */
         @Override
         public void close() {
@@ -2128,8 +2174,8 @@
         }
 
         /**
-         * Set the default buffer size for the SurfaceControl, if there is an
-         * {@link Surface} assosciated with the control, then
+         * Set the default buffer size for the SurfaceControl, if there is a
+         * {@link Surface} associated with the control, then
          * this will be the default size for buffers dequeued from it.
          * @param sc The surface to set the buffer size for.
          * @param w The default width
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ee8d663..e931448 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -491,7 +491,7 @@
         if (mBackgroundControl == null) {
             return;
         }
-        if ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) {
+        if ((mSubLayer > 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
             mBackgroundControl.show();
             mBackgroundControl.setLayer(Integer.MIN_VALUE);
         } else {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75067d3..2357db4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28200,11 +28200,11 @@
         final Rect mOutsets = new Rect();
 
         /**
-         * In multi-window we force show the navigation bar. Because we don't want that the surface
-         * size changes in this mode, we instead have a flag whether the navigation bar size should
-         * always be consumed, so the app is treated like there is no virtual navigation bar at all.
+         * In multi-window we force show the system bars. Because we don't want that the surface
+         * size changes in this mode, we instead have a flag whether the system bars sizes should
+         * always be consumed, so the app is treated like there are no virtual system bars at all.
          */
-        boolean mAlwaysConsumeNavBar;
+        boolean mAlwaysConsumeSystemBars;
 
         /**
          * The internal insets given by this window.  This value is
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a4d80dc..4851476 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -142,7 +142,7 @@
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768704)
     protected OnHierarchyChangeListener mOnHierarchyChangeListener;
 
     // The view contained within this ViewGroup that has or contains focus.
@@ -239,7 +239,7 @@
             @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
                     name = "PADDING_NOT_NULL")
     }, formatToHexString = true)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769411)
     protected int mGroupFlags;
 
     /**
@@ -300,7 +300,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769377)
     protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
 
     /**
@@ -314,7 +314,7 @@
      *
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769647)
     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
 
     // UNUSED FLAG VALUE: 0x1000;
@@ -368,7 +368,7 @@
      * When set, this ViewGroup should not intercept touch events.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123983692)
     protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6d04cd31..2880e7f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -512,7 +512,7 @@
     final Rect mPendingBackDropFrame = new Rect();
     final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
             new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
-    boolean mPendingAlwaysConsumeNavBar;
+    boolean mPendingAlwaysConsumeSystemBars;
     private InsetsState mTempInsets = new InsetsState();
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
@@ -921,9 +921,9 @@
                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
                 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
-                mAttachInfo.mAlwaysConsumeNavBar =
-                        (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
-                mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
+                mAttachInfo.mAlwaysConsumeSystemBars =
+                        (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
+                mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
                 mInsetsController.onStateChanged(mTempInsets);
                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
@@ -1918,12 +1918,12 @@
             if (sNewInsetsMode != NEW_INSETS_MODE_NONE) {
                 mLastWindowInsets = mInsetsController.calculateInsets(
                         mContext.getResources().getConfiguration().isScreenRound(),
-                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout,
+                        mAttachInfo.mAlwaysConsumeSystemBars, displayCutout,
                         contentInsets, stableInsets, mWindowAttributes.softInputMode);
             } else {
                 mLastWindowInsets = new WindowInsets(contentInsets, stableInsets,
                         mContext.getResources().getConfiguration().isScreenRound(),
-                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
+                        mAttachInfo.mAlwaysConsumeSystemBars, displayCutout);
             }
         }
         return mLastWindowInsets;
@@ -2126,7 +2126,7 @@
                 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
                     insetsChanged = true;
                 }
-                if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
+                if (mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars) {
                     insetsChanged = true;
                 }
                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
@@ -2326,8 +2326,8 @@
                 final boolean surfaceSizeChanged = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
                 surfaceChanged |= surfaceSizeChanged;
-                final boolean alwaysConsumeNavBarChanged =
-                        mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
+                final boolean alwaysConsumeSystemBarsChanged =
+                        mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
                 final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
                 if (contentInsetsChanged) {
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
@@ -2356,8 +2356,8 @@
                     // Need to relayout with content insets.
                     contentInsetsChanged = true;
                 }
-                if (alwaysConsumeNavBarChanged) {
-                    mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
+                if (alwaysConsumeSystemBarsChanged) {
+                    mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
                     contentInsetsChanged = true;
                 }
                 if (contentInsetsChanged || mLastSystemUiVisibility !=
@@ -4633,7 +4633,7 @@
                         mPendingOutsets.set((Rect) args.arg7);
                         mPendingBackDropFrame.set((Rect) args.arg8);
                         mForceNextWindowRelayout = args.argi1 != 0;
-                        mPendingAlwaysConsumeNavBar = args.argi2 != 0;
+                        mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
 
                         args.recycle();
 
@@ -7084,8 +7084,8 @@
             destroySurface();
         }
 
-        mPendingAlwaysConsumeNavBar =
-                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
+        mPendingAlwaysConsumeSystemBars =
+                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
 
         if (restore) {
             params.restore();
@@ -7374,7 +7374,7 @@
     private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
             MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-            boolean alwaysConsumeNavBar, int displayId,
+            boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) {
         if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
@@ -7414,7 +7414,7 @@
         args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
         args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
         args.argi1 = forceLayout ? 1 : 0;
-        args.argi2 = alwaysConsumeNavBar ? 1 : 0;
+        args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
         args.argi3 = displayId;
         msg.obj = args;
         mHandler.sendMessage(msg);
@@ -8498,13 +8498,14 @@
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-                boolean alwaysConsumeNavBar, int displayId,
+                boolean alwaysConsumeSystemBars, int displayId,
                 DisplayCutout.ParcelableWrapper displayCutout) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
                         visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
-                        backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
+                        backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId,
+                        displayCutout);
             }
         }
 
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index aac0e34..ffa769a 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -83,7 +83,7 @@
      * changes in this mode, we instead have a flag whether the navigation bar size should always
      * be consumed, so the app is treated like there is no virtual navigation bar at all.
      */
-    private final boolean mAlwaysConsumeNavBar;
+    private final boolean mAlwaysConsumeSystemBars;
 
     private final boolean mSystemWindowInsetsConsumed;
     private final boolean mStableInsetsConsumed;
@@ -111,10 +111,10 @@
      * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
      */
     public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
-            boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
+            boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
         this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
                 createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
-                isRound, alwaysConsumeNavBar, displayCutout);
+                isRound, alwaysConsumeSystemBars, displayCutout);
     }
 
     /**
@@ -133,7 +133,7 @@
             @Nullable Insets[] typeMaxInsetsMap,
             boolean[] typeVisibilityMap,
             boolean isRound,
-            boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
+            boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
         mSystemWindowInsetsConsumed = typeInsetsMap == null;
         mTypeInsetsMap = mSystemWindowInsetsConsumed
                 ? new Insets[SIZE]
@@ -146,7 +146,7 @@
 
         mTypeVisibilityMap = typeVisibilityMap;
         mIsRound = isRound;
-        mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+        mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
 
         mDisplayCutoutConsumed = displayCutout == null;
         mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
@@ -160,7 +160,7 @@
      */
     public WindowInsets(WindowInsets src) {
         this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mTypeVisibilityMap, src.mIsRound,
-                src.mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(src));
+                src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
     }
 
     private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
@@ -443,7 +443,7 @@
         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mTypeVisibilityMap,
-                mIsRound, mAlwaysConsumeNavBar,
+                mIsRound, mAlwaysConsumeSystemBars,
                 null /* displayCutout */);
     }
 
@@ -489,7 +489,7 @@
     public WindowInsets consumeSystemWindowInsets() {
         return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mTypeVisibilityMap,
-                mIsRound, mAlwaysConsumeNavBar,
+                mIsRound, mAlwaysConsumeSystemBars,
                 displayCutoutCopyConstructorArgument(this));
     }
 
@@ -729,15 +729,15 @@
     @NonNull
     public WindowInsets consumeStableInsets() {
         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
-                mTypeVisibilityMap, mIsRound, mAlwaysConsumeNavBar,
+                mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
                 displayCutoutCopyConstructorArgument(this));
     }
 
     /**
      * @hide
      */
-    public boolean shouldAlwaysConsumeNavBar() {
-        return mAlwaysConsumeNavBar;
+    public boolean shouldAlwaysConsumeSystemBars() {
+        return mAlwaysConsumeSystemBars;
     }
 
     @Override
@@ -809,7 +809,7 @@
                         ? null
                         : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
                 mTypeVisibilityMap,
-                mIsRound, mAlwaysConsumeNavBar,
+                mIsRound, mAlwaysConsumeSystemBars,
                 mDisplayCutoutConsumed
                         ? null
                         : mDisplayCutout == null
@@ -824,7 +824,7 @@
         WindowInsets that = (WindowInsets) o;
 
         return mIsRound == that.mIsRound
-                && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
+                && mAlwaysConsumeSystemBars == that.mAlwaysConsumeSystemBars
                 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
                 && mStableInsetsConsumed == that.mStableInsetsConsumed
                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
@@ -837,8 +837,9 @@
     @Override
     public int hashCode() {
         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
-                Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mAlwaysConsumeNavBar,
-                mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
+                Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout,
+                mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
+                mDisplayCutoutConsumed);
     }
 
 
@@ -900,7 +901,7 @@
         private DisplayCutout mDisplayCutout;
 
         private boolean mIsRound;
-        private boolean mAlwaysConsumeNavBar;
+        private boolean mAlwaysConsumeSystemBars;
 
         /**
          * Creates a builder where all insets are initially consumed.
@@ -924,7 +925,7 @@
             mStableInsetsConsumed = insets.mStableInsetsConsumed;
             mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
             mIsRound = insets.mIsRound;
-            mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
+            mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
         }
 
         /**
@@ -1119,8 +1120,8 @@
 
         /** @hide */
         @NonNull
-        public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) {
-            mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+        public Builder setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars) {
+            mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
             return this;
         }
 
@@ -1133,7 +1134,7 @@
         public WindowInsets build() {
             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
                     mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
-                    mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
+                    mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
         }
     }
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 453c5e3..8a111cf 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -93,11 +93,11 @@
     public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
 
     /**
-     * In multi-window we force show the navigation bar. Because we don't want that the surface size
-     * changes in this mode, we instead have a flag whether the navigation bar size should always be
-     * consumed, so the app is treated like there is no virtual navigation bar at all.
+     * In multi-window we force show the system bars. Because we don't want that the surface size
+     * changes in this mode, we instead have a flag whether the system bar sizes should always be
+     * consumed, so the app is treated like there is no virtual system bars at all.
      */
-    public static final int RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR = 0x40;
+    public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40;
 
     /**
      * Flag for relayout: the client will be later giving
@@ -118,9 +118,10 @@
     public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
 
     /**
-     * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR}, but as a "hint" when adding the window.
+     * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS}, but as a "hint" when adding the
+     * window.
      */
-    public static final int ADD_FLAG_ALWAYS_CONSUME_NAV_BAR = 0x4;
+    public static final int ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS = 0x4;
 
     public static final int ADD_OKAY = 0;
     public static final int ADD_BAD_APP_TOKEN = -1;
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 35ed7bf..46a59f0 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -54,6 +54,16 @@
     int NAV_BAR_RIGHT = 1 << 1;
     int NAV_BAR_BOTTOM = 1 << 2;
 
+    // Navigation bar interaction modes
+    int NAV_BAR_MODE_3BUTTON = 0;
+    int NAV_BAR_MODE_2BUTTON = 1;
+    int NAV_BAR_MODE_GESTURAL = 2;
+
+    // Associated overlays for each nav bar mode
+    String NAV_BAR_MODE_3BUTTON_OVERLAY = "com.android.internal.systemui.navbar.threebutton";
+    String NAV_BAR_MODE_2BUTTON_OVERLAY = "com.android.internal.systemui.navbar.twobutton";
+    String NAV_BAR_MODE_GESTURAL_OVERLAY = "com.android.internal.systemui.navbar.gestural";
+
     /**
      * Broadcast sent when a user activity is detected.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 384cdbb..d12777f 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -848,7 +848,7 @@
         if (mRequestPreparerLists == null) {
             mRequestPreparerLists = new SparseArray<>(1);
         }
-        int id = preparer.getView().getAccessibilityViewId();
+        int id = preparer.getAccessibilityViewId();
         List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(id);
         if (requestPreparerList == null) {
             requestPreparerList = new ArrayList<>(1);
@@ -864,7 +864,7 @@
         if (mRequestPreparerLists == null) {
             return;
         }
-        int viewId = preparer.getView().getAccessibilityViewId();
+        int viewId = preparer.getAccessibilityViewId();
         List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(viewId);
         if (requestPreparerList != null) {
             requestPreparerList.remove(preparer);
diff --git a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
index 4dcb187..8108d37 100644
--- a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
+++ b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
@@ -51,6 +51,7 @@
     public @interface RequestTypes {}
 
     private final WeakReference<View> mViewRef;
+    private final int mAccessibilityViewId;
     private final int mRequestTypes;
 
     /**
@@ -68,6 +69,7 @@
             throw new IllegalStateException("View must be attached to a window");
         }
         mViewRef = new WeakReference<>(view);
+        mAccessibilityViewId = view.getAccessibilityViewId();
         mRequestTypes = requestTypes;
         view.addOnAttachStateChangeListener(new ViewAttachStateListener());
     }
@@ -118,4 +120,8 @@
             v.removeOnAttachStateChangeListener(this);
         }
     }
+
+    int getAccessibilityViewId() {
+        return mAccessibilityViewId;
+    }
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8cb04cb..77a0c4c 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,7 +16,6 @@
 
 package android.view.autofill;
 
-import static android.service.autofill.FillRequest.FLAG_AUGMENTED_AUTOFILL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.Helper.sDebug;
 import static android.view.autofill.Helper.sVerbose;
@@ -228,6 +227,7 @@
     /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1;
     /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
     /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
+    /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
 
     /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
 
@@ -520,6 +520,13 @@
     @GuardedBy("mLock")
     private boolean mForAugmentedAutofillOnly;
 
+    /**
+     * When set, standard autofill is enabled, but sessions can still be created for augmented
+     * autofill only.
+     */
+    @GuardedBy("mLock")
+    private boolean mEnabledForAugmentedAutofillOnly;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -946,7 +953,7 @@
 
         ensureServiceClientAddedIfNeededLocked();
 
-        if (!mEnabled) {
+        if (!mEnabled && !mEnabledForAugmentedAutofillOnly) {
             if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
 
             if (mCallback != null) {
@@ -988,7 +995,7 @@
     void notifyViewExitedLocked(@NonNull View view) {
         ensureServiceClientAddedIfNeededLocked();
 
-        if (mEnabled && isActiveLocked()) {
+        if ((mEnabled || mEnabledForAugmentedAutofillOnly) && isActiveLocked()) {
             // dont notify exited when Activity is already in background
             if (!isClientDisablingEnterExitEvent()) {
                 final AutofillId id = view.getAutofillId();
@@ -1104,7 +1111,7 @@
 
         ensureServiceClientAddedIfNeededLocked();
 
-        if (!mEnabled) {
+        if (!mEnabled && !mEnabledForAugmentedAutofillOnly) {
             if (sVerbose) {
                 Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
             }
@@ -1155,7 +1162,7 @@
     private void notifyViewExitedLocked(@NonNull View view, int virtualId) {
         ensureServiceClientAddedIfNeededLocked();
 
-        if (mEnabled && isActiveLocked()) {
+        if ((mEnabled || mEnabledForAugmentedAutofillOnly) && isActiveLocked()) {
             // don't notify exited when Activity is already in background
             if (!isClientDisablingEnterExitEvent()) {
                 final AutofillId id = getAutofillId(view, virtualId);
@@ -1674,14 +1681,17 @@
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
         if (mEnteredForAugmentedAutofillIds != null
-                && mEnteredForAugmentedAutofillIds.contains(id)) {
+                && mEnteredForAugmentedAutofillIds.contains(id)
+                || mEnabledForAugmentedAutofillOnly) {
             if (sVerbose) Log.v(TAG, "Starting session for augmented autofill on " + id);
-            flags |= FLAG_AUGMENTED_AUTOFILL_REQUEST;
+            flags |= FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
         }
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
                     + ", flags=" + flags + ", state=" + getStateAsStringLocked()
                     + ", compatMode=" + isCompatibilityModeEnabledLocked()
+                    + ", augmentedOnly=" + mForAugmentedAutofillOnly
+                    + ", enabledAugmentedOnly=" + mEnabledForAugmentedAutofillOnly
                     + ", enteredIds=" + mEnteredIds);
         }
         if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
@@ -1776,7 +1786,8 @@
 
     @GuardedBy("mLock")
     private void ensureServiceClientAddedIfNeededLocked() {
-        if (getClient() == null) {
+        final AutofillClient client = getClient();
+        if (client == null) {
             return;
         }
 
@@ -1785,11 +1796,18 @@
             try {
                 final int userId = mContext.getUserId();
                 final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
-                mService.addClient(mServiceClient, userId, receiver);
+                mService.addClient(mServiceClient, client.autofillClientGetComponentName(),
+                        userId, receiver);
                 final int flags = receiver.getIntResult();
                 mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
                 sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
                 sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
+                mEnabledForAugmentedAutofillOnly = (flags
+                        & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
+                if (sVerbose) {
+                    Log.v(TAG, "receiver results: flags=" + flags + " enabled=" + mEnabled
+                            + ", enabledForAugmentedOnly: " + mEnabledForAugmentedAutofillOnly);
+                }
                 final IAutoFillManager service = mService;
                 final IAutoFillManagerClient serviceClient = mServiceClient;
                 mServiceClientCleaner = Cleaner.create(this, () -> {
@@ -2406,6 +2424,7 @@
             pw.print(" ("); pw.print(client.autofillClientGetActivityToken()); pw.println(')');
         }
         pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
+        pw.print(pfx); pw.print("enabledAugmentedOnly: "); pw.println(mForAugmentedAutofillOnly);
         pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
         pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
         pw.print(pfx); pw.print("onInvisibleCalled "); pw.println(mOnInvisibleCalled);
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 9e6a4af..a507e74 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -37,7 +37,8 @@
  */
 oneway interface IAutoFillManager {
     // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
-    void addClient(in IAutoFillManagerClient client, int userId, in IResultReceiver result);
+    void addClient(in IAutoFillManagerClient client, in ComponentName componentName, int userId,
+        in IResultReceiver result);
     void removeClient(in IAutoFillManagerClient client, int userId);
     void startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
         in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index a3e6549..9e546a8 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
@@ -52,11 +53,13 @@
     private static final String TAG = ContentCaptureManager.class.getSimpleName();
 
     /** @hide */
+    public static final int RESULT_CODE_OK = 0;
+    /** @hide */
     public static final int RESULT_CODE_TRUE = 1;
     /** @hide */
     public static final int RESULT_CODE_FALSE = 2;
     /** @hide */
-    public static final int RESULT_CODE_NOT_SERVICE = -1;
+    public static final int RESULT_CODE_SECURITY_EXCEPTION = -1;
 
     /**
      * Timeout for calls to system_server.
@@ -243,6 +246,7 @@
     @UiThread
     public void onActivityCreated(@NonNull IBinder applicationToken,
             @NonNull ComponentName activityComponent, int flags) {
+        if (mOptions.lite) return;
         synchronized (mLock) {
             mFlags |= flags;
             getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
@@ -252,18 +256,21 @@
     /** @hide */
     @UiThread
     public void onActivityResumed() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().notifySessionLifecycle(/* started= */ true);
     }
 
     /** @hide */
     @UiThread
     public void onActivityPaused() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().notifySessionLifecycle(/* started= */ false);
     }
 
     /** @hide */
     @UiThread
     public void onActivityDestroyed() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().destroy();
     }
 
@@ -276,6 +283,7 @@
      */
     @UiThread
     public void flush(@FlushReason int reason) {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().flush(reason);
     }
 
@@ -285,7 +293,7 @@
      */
     @Nullable
     public ComponentName getServiceComponentName() {
-        if (!isContentCaptureEnabled()) return null;
+        if (!isContentCaptureEnabled() && !mOptions.lite) return null;
 
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
@@ -297,6 +305,35 @@
     }
 
     /**
+     * Gets the (optional) intent used to launch the service-specific settings.
+     *
+     * <p>This method is static because it's called by Settings, which might not be whitelisted
+     * for content capture (in which case the ContentCaptureManager on its context would be null).
+     *
+     * @hide
+     */
+    // TODO: use "lite" options as it's done by activities from the content capture service
+    @Nullable
+    public static ComponentName getServiceSettingsComponentName() {
+        final IBinder binder = ServiceManager
+                .checkService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
+        if (binder == null) return null;
+
+        final IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(binder);
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        try {
+            service.getServiceSettingsActivity(resultReceiver);
+            final int resultCode = resultReceiver.getIntResult();
+            if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
+                throw new SecurityException(resultReceiver.getStringResult());
+            }
+            return resultReceiver.getParcelableResult();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks whether content capture is enabled for this activity.
      *
      * <p>There are many reasons it could be disabled, such as:
@@ -311,6 +348,8 @@
      * </ul>
      */
     public boolean isContentCaptureEnabled() {
+        if (mOptions.lite) return false;
+
         final MainContentCaptureSession mainSession;
         synchronized (mLock) {
             mainSession = mMainSession;
@@ -365,7 +404,7 @@
                 return true;
             case RESULT_CODE_FALSE:
                 return false;
-            case RESULT_CODE_NOT_SERVICE:
+            case RESULT_CODE_SECURITY_EXCEPTION:
                 throw new SecurityException("caller is not user's ContentCapture service");
             default:
                 Log.wtf(TAG, "received invalid result: " + resultCode);
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 6d41b28..ed1ca2a 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -135,11 +135,18 @@
     public static final int STATE_SERVICE_DIED = 0x400;
 
     /**
+     * Session is disabled because the service package is being udpated.
+     *
+     * @hide
+     */
+    public static final int STATE_SERVICE_UPDATING = 0x800;
+
+    /**
      * Session is enabled, after the service died and came back to live.
      *
      * @hide
      */
-    public static final int STATE_SERVICE_RESURRECTED = 0x800;
+    public static final int STATE_SERVICE_RESURRECTED = 0x1000;
 
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index e3b0372..15fbaa2 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -67,4 +67,9 @@
      * Returns whether the content capture feature is enabled for the calling user.
      */
     void isContentCaptureFeatureEnabled(in IResultReceiver result);
+
+    /**
+     * Returns a ComponentName with the name of custom service activity, if defined.
+     */
+    void getServiceSettingsActivity(in IResultReceiver result);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 666af59..790b8f9 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -230,7 +230,8 @@
 
     /**
      * Callback from {@code system_server} after call to
-     * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int, IBinder)}
+     * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int,
+     * IResultReceiver)}.
      *
      * @param resultCode session state
      * @param binder handle to {@code IContentCaptureDirectManager}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index cb44f79..0f2e702e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -86,7 +86,8 @@
             new File("/data/misc/textclassifier/lang_id.model");
 
     // Actions
-    private static final String ACTIONS_FACTORY_MODEL_FILENAME_REGEX = "actions_suggestions.model";
+    private static final String ACTIONS_FACTORY_MODEL_FILENAME_REGEX =
+            "actions_suggestions\\.(.*)\\.model";
     private static final File UPDATED_ACTIONS_MODEL =
             new File("/data/misc/textclassifier/actions_suggestions.model");
 
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
new file mode 100644
index 0000000..3576b6b
--- /dev/null
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -0,0 +1,63 @@
+package com.android.internal.app;
+
+import android.content.ComponentName;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Used to sort resolved activities in {@link ResolverListController}.
+ */
+abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {
+
+    protected AfterCompute mAfterCompute;
+
+    /**
+     * Callback to be called when {@link #compute(List)} finishes. This signals to stop waiting.
+     */
+    public interface AfterCompute {
+
+        public void afterCompute();
+    }
+
+    public void setCallBack(AfterCompute afterCompute) {
+        mAfterCompute = afterCompute;
+    }
+
+    /**
+     * Computes features for each target. This will be called before calls to {@link
+     * #getScore(ComponentName)} or {@link #compare(Object, Object)}, in order to prepare the
+     * comparator for those calls. Note that {@link #getScore(ComponentName)} uses {@link
+     * ComponentName}, so the implementation will have to be prepared to identify a {@link
+     * ResolvedComponentInfo} by {@link ComponentName}.
+     */
+    public abstract void compute(List<ResolvedComponentInfo> targets);
+
+    /**
+     * Returns the score that was calculated for the corresponding {@link ResolvedComponentInfo}
+     * when {@link #compute(List)} was called before this.
+     */
+    public abstract float getScore(ComponentName name);
+
+    /**
+     * Reports to UsageStats what was chosen.
+     */
+    // TODO(b/129014961) Move implemetation here and make final.
+    public abstract void updateChooserCounts(String packageName, int userId, String action);
+
+    /**
+     * Updates the model used to rank the componentNames.
+     *
+     * <p>Default implementation does nothing, as we could have simple model that does not train
+     * online.
+     *
+     * @param componentName the component that the user clicked
+     */
+    public void updateModel(ComponentName componentName) {
+    }
+
+    /**
+     * Called when the {@link ResolverActivity} is destroyed.
+     */
+    public abstract void destroy();
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index faf0c7d..54fff9b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -58,6 +58,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.metrics.LogMaker;
@@ -236,7 +237,7 @@
                     if (DEBUG) {
                         Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
                     }
-                    if (isDestroyed()) {
+                    if (mChooserListAdapter == null || isDestroyed()) {
                         break;
                     }
                     unbindRemainingServices();
@@ -821,6 +822,7 @@
             mRefinementResultReceiver = null;
         }
         unbindRemainingServices();
+        mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
         mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
         if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
             mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback);
@@ -876,10 +878,17 @@
         }
         mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
         mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
-        adapterView.setAdapter(mChooserRowAdapter);
         if (listView != null) {
             listView.setItemsCanFocus(true);
+            listView.addOnLayoutChangeListener(
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                        if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left)) {
+                            adapterView.setAdapter(mChooserRowAdapter);
+                        }
+                    });
         }
+
+        adapterView.setAdapter(mChooserRowAdapter);
     }
 
     @Override
@@ -1269,11 +1278,10 @@
         }
         mAppPredictor.notifyAppTargetEvent(
                 new AppTargetEvent.Builder(
-                    new AppTarget(
-                        new AppTargetId(shortcutId),
-                        componentName.getPackageName(),
-                        componentName.getClassName(),
-                        getUser()),
+                    new AppTarget.Builder(new AppTargetId(shortcutId))
+                        .setTarget(componentName.getPackageName(), getUser())
+                        .setClassName(componentName.getClassName())
+                        .build(),
                     AppTargetEvent.ACTION_LAUNCH
                 ).setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE)
                 .build());
@@ -1465,14 +1473,6 @@
             return null;
         }
 
-        public Drawable getBadgeIcon() {
-            return null;
-        }
-
-        public CharSequence getBadgeContentDescription() {
-            return null;
-        }
-
         public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
             return null;
         }
@@ -1561,31 +1561,49 @@
          */
         // TODO(121287224): Refactor code to apply the suggestion above
         private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
+            Drawable directShareIcon = null;
+
+            // First get the target drawable and associated activity info
             final Icon icon = target.getIcon();
             if (icon != null) {
-                return icon.loadDrawable(ChooserActivity.this);
-            }
-            if (!USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
-                return null;
+                directShareIcon = icon.loadDrawable(ChooserActivity.this);
+            } else if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+                Bundle extras = target.getIntentExtras();
+                if (extras != null && extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
+                    CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
+                    LauncherApps launcherApps = (LauncherApps) getSystemService(
+                            Context.LAUNCHER_APPS_SERVICE);
+                    final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
+                    q.setPackage(target.getComponentName().getPackageName());
+                    q.setShortcutIds(Arrays.asList(shortcutId.toString()));
+                    q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
+                    final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
+                    if (shortcuts != null && shortcuts.size() > 0) {
+                        directShareIcon = launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
+                    }
+                }
             }
 
-            Bundle extras = target.getIntentExtras();
-            if (extras == null || !extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
-                return null;
-            }
-            CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
-            LauncherApps launcherApps = (LauncherApps) getSystemService(
-                    Context.LAUNCHER_APPS_SERVICE);
-            final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
-            q.setPackage(target.getComponentName().getPackageName());
-            q.setShortcutIds(Arrays.asList(shortcutId.toString()));
-            q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
-            final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
-            if (shortcuts != null && shortcuts.size() > 0) {
-                return launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
+            if (directShareIcon == null) return null;
+
+            ActivityInfo info = null;
+            try {
+                info = mPm.getActivityInfo(target.getComponentName(), 0);
+            } catch (NameNotFoundException error) {
+                Log.e(TAG, "Could not find activity associated with ChooserTarget");
             }
 
-            return null;
+            if (info == null) return null;
+
+            // Now fetch app icon and raster with no badging even in work profile
+            Bitmap appIcon = (new ActivityInfoPresentationGetter(info)).getIconBitmap();
+
+            // Raster target drawable with appIcon as a badge
+            SimpleIconFactory sif = SimpleIconFactory.obtain(ChooserActivity.this);
+            Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
+            sif.recycle();
+
+            return new BitmapDrawable(getResources(), directShareBadgedIcon);
         }
 
         public float getModifiedScore() {
@@ -1683,16 +1701,6 @@
             return mDisplayIcon;
         }
 
-        @Override
-        public Drawable getBadgeIcon() {
-            return mBadgeIcon;
-        }
-
-        @Override
-        public CharSequence getBadgeContentDescription() {
-            return mBadgeContentDescription;
-        }
-
         public ChooserTarget getChooserTarget() {
             return mChooserTarget;
         }
@@ -2062,7 +2070,7 @@
     class ChooserRowAdapter extends BaseAdapter {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
-        private int mAnimationCount = 0;
+        private int mCalculatedMaxTargetsPerRow = MAX_TARGETS_PER_ROW_LANDSCAPE;
 
         private DirectShareViewHolder mDirectShareViewHolder;
 
@@ -2070,6 +2078,9 @@
         private static final int VIEW_TYPE_NORMAL = 1;
         private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
 
+        private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
+        private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
+
         public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
@@ -2089,9 +2100,40 @@
             });
         }
 
+        /**
+         * Determine how many targets can comfortably fit in a single row.
+         *
+         * @param width The new row width to use for recalculation
+         * @return true if the numbers of targets per row has changed
+         */
+        public boolean calculateMaxTargetsPerRow(int width) {
+            int targetWidth = getResources().getDimensionPixelSize(
+                    R.dimen.chooser_target_width);
+
+            if (targetWidth == 0 || width == 0) {
+                return false;
+            }
+
+            int margin = getResources().getDimensionPixelSize(
+                    R.dimen.chooser_edge_margin_normal);
+
+            int newCount =  (width - margin * 2) / targetWidth;
+            if (newCount != mCalculatedMaxTargetsPerRow) {
+                mCalculatedMaxTargetsPerRow = newCount;
+                return true;
+            }
+
+            return false;
+        }
+
         private int getMaxTargetsPerRow() {
-            // this will soon hold logic for portrait/landscape
-            return 4;
+            int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
+            if (getResources().getConfiguration().orientation
+                    == Configuration.ORIENTATION_LANDSCAPE) {
+                maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
+            }
+
+            return Math.min(maxTargets, mCalculatedMaxTargetsPerRow);
         }
 
         @Override
@@ -2158,9 +2200,7 @@
                 holder = (RowViewHolder) convertView.getTag();
             }
 
-            bindViewHolder(position, holder,
-                    viewType == VIEW_TYPE_DIRECT_SHARE
-                            ? ChooserListAdapter.MAX_SERVICE_TARGETS : getMaxTargetsPerRow());
+            bindViewHolder(position, holder);
 
             return holder.getViewGroup();
         }
@@ -2277,7 +2317,7 @@
             }
         }
 
-        void bindViewHolder(int rowPosition, RowViewHolder holder, int columnCount) {
+        void bindViewHolder(int rowPosition, RowViewHolder holder) {
             final int start = getFirstRowPosition(rowPosition);
             final int startType = mChooserListAdapter.getPositionTargetType(start);
 
@@ -2294,6 +2334,7 @@
                 setVertPadding(row, 0, 0);
             }
 
+            int columnCount = holder.getColumnCount();
             int end = start + columnCount - 1;
             while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) {
                 end--;
@@ -2328,36 +2369,15 @@
             for (int i = 0; i < columnCount; i++) {
                 final View v = holder.getView(i);
                 if (start + i <= end) {
-                    setCellVisibility(holder, i, View.VISIBLE);
+                    holder.setViewVisibility(i, View.VISIBLE);
                     holder.setItemIndex(i, start + i);
                     mChooserListAdapter.bindView(holder.getItemIndex(i), v);
                 } else {
-                    setCellVisibility(holder, i, View.INVISIBLE);
+                    holder.setViewVisibility(i, View.INVISIBLE);
                 }
             }
         }
 
-        private void setCellVisibility(RowViewHolder holder, int i, int visibility) {
-            final View v = holder.getView(i);
-            if (visibility == View.VISIBLE) {
-                holder.setViewVisibility(i, true);
-                v.setVisibility(visibility);
-                v.setAlpha(1.0f);
-            } else if (visibility == View.INVISIBLE && holder.getViewVisibility(i)) {
-                holder.setViewVisibility(i, false);
-
-                ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
-                fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS);
-                fadeAnim.setInterpolator(new AccelerateInterpolator(1.0f));
-                fadeAnim.addListener(new AnimatorListenerAdapter() {
-                    public void onAnimationEnd(Animator animation) {
-                        v.setVisibility(View.INVISIBLE);
-                    }
-                });
-                fadeAnim.start();
-            }
-        }
-
         private void setVertPadding(ViewGroup row, int top, int bottom) {
             row.setPadding(row.getPaddingLeft(), top, row.getPaddingRight(), bottom);
         }
@@ -2393,13 +2413,11 @@
         protected int mMeasuredRowHeight;
         private int[] mItemIndices;
         protected final View[] mCells;
-        private final boolean[] mCellVisibility;
         private final int mColumnCount;
 
         RowViewHolder(int cellCount) {
             this.mCells = new View[cellCount];
             this.mItemIndices = new int[cellCount];
-            this.mCellVisibility = new boolean[cellCount];
             this.mColumnCount = cellCount;
         }
 
@@ -2409,18 +2427,12 @@
 
         abstract ViewGroup getRow(int index);
 
+        abstract void setViewVisibility(int i, int visibility);
+
         public int getColumnCount() {
             return mColumnCount;
         }
 
-        public void setViewVisibility(int index, boolean visibility) {
-            mCellVisibility[index] = visibility;
-        }
-
-        public boolean getViewVisibility(int index) {
-            return mCellVisibility[index];
-        }
-
         public void measure() {
             final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
             getViewGroup().measure(spec, spec);
@@ -2476,6 +2488,10 @@
 
             return mRow;
         }
+
+        public void setViewVisibility(int i, int visibility) {
+            getView(i).setVisibility(visibility);
+        }
     }
 
     class DirectShareViewHolder extends RowViewHolder {
@@ -2488,12 +2504,15 @@
         private int mDirectShareCurrHeight = 0;
         private int mDirectShareMaxHeight = 0;
 
+        private final boolean[] mCellVisibility;
+
         DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
             super(rows.size() * cellCountPerRow);
 
             this.mParent = parent;
             this.mRows = rows;
             this.mCellCountPerRow = cellCountPerRow;
+            this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
         }
 
         public ViewGroup addView(int index, View v) {
@@ -2532,6 +2551,27 @@
             return mDirectShareCurrHeight;
         }
 
+        public void setViewVisibility(int i, int visibility) {
+            final View v = getView(i);
+            if (visibility == View.VISIBLE) {
+                mCellVisibility[i] = true;
+                v.setVisibility(visibility);
+                v.setAlpha(1.0f);
+            } else if (visibility == View.INVISIBLE && mCellVisibility[i]) {
+                mCellVisibility[i] = false;
+
+                ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
+                fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS);
+                fadeAnim.setInterpolator(new AccelerateInterpolator(1.0f));
+                fadeAnim.addListener(new AnimatorListenerAdapter() {
+                    public void onAnimationEnd(Animator animation) {
+                        v.setVisibility(View.INVISIBLE);
+                    }
+                });
+                fadeAnim.start();
+            }
+        }
+
         public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
             // only expand if we have more than 4 targets, and delay that decision until
             // they start to scroll
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 12942ab..21152ae 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -42,7 +42,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Color;
+import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -133,8 +133,6 @@
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
-    SimpleIconFactory mSimpleIconFactory;
-
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override public void onSomePackagesChanged() {
             mAdapter.handlePackagesChanged();
@@ -311,11 +309,6 @@
         // as to mitigate Intent Capturing vulnerability
         mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;
 
-        final int iconSize = getResources().getDimensionPixelSize(R.dimen.resolver_icon_size);
-        final int badgeSize = getResources().getDimensionPixelSize(R.dimen.resolver_badge_size);
-        mSimpleIconFactory = new SimpleIconFactory(this, mIconDpi, iconSize, badgeSize);
-        mSimpleIconFactory.setWrapperBackgroundColor(Color.WHITE);
-
         if (configureContentView(mIntents, initialIntents, rList)) {
             return;
         }
@@ -500,64 +493,150 @@
         }
     }
 
-    @Nullable
-    Drawable getIcon(Resources res, int resId) {
-        Drawable result;
-        try {
-            result = res.getDrawableForDensity(resId, mIconDpi);
-        } catch (Resources.NotFoundException e) {
-            result = null;
-        }
-
-        return result;
-    }
 
     /**
-     * Loads the icon for the provided ResolveInfo. Defaults to using the application icon over
+     * Loads the icon for the provided ApplicationInfo. Defaults to using the application icon over
      * any IntentFilter or Activity icon to increase user understanding, with an exception for
      * applications that hold the right permission. Always attempts to use icon resources over
      * PackageManager loading mechanisms so badging can be done by iconloader.
      */
-    Drawable loadIconForResolveInfo(ResolveInfo ri) {
-        Drawable dr = null;
+    private abstract class TargetPresentationGetter {
+        @Nullable abstract Drawable getIconSubstitute();
+        @Nullable abstract String getAppSubLabel();
 
-        // Allow for app icon override given the right permission
-        if (PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
-                android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
-                ri.activityInfo.applicationInfo.packageName)) {
-            try {
-                if (ri.resolvePackageName != null && ri.icon != 0) {
-                    dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
-                }
-                if (dr == null) {
-                    final int iconRes = ri.getIconResource();
-                    if (iconRes != 0) {
-                        dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName),
-                                iconRes);
+        private final ApplicationInfo mAi;
+        private final boolean mHasSubstitutePermission;
+
+        TargetPresentationGetter(ApplicationInfo ai) {
+            mAi = ai;
+            mHasSubstitutePermission = PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
+                    android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
+                    mAi.packageName);
+        }
+
+        Drawable getIcon() {
+            return new BitmapDrawable(getResources(), getIconBitmap());
+        }
+
+        Bitmap getIconBitmap() {
+            Drawable dr = null;
+            if (mHasSubstitutePermission) {
+                dr = getIconSubstitute();
+            }
+
+            if (dr == null) {
+                try {
+                    if (mAi.icon != 0) {
+                        dr = loadIconFromResource(mPm.getResourcesForApplication(mAi), mAi.icon);
                     }
+                } catch (NameNotFoundException ignore) {
+                }
+            }
+
+            // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
+            if (dr == null) {
+                dr = mAi.loadIcon(mPm);
+            }
+
+            SimpleIconFactory sif = SimpleIconFactory.obtain(ResolverActivity.this);
+            Bitmap icon = sif.createUserBadgedIconBitmap(dr, Process.myUserHandle());
+            sif.recycle();
+
+            return icon;
+        }
+
+        String getLabel() {
+            String label = null;
+            // Apps with the substitute permission will always show the sublabel as their label
+            if (mHasSubstitutePermission) {
+                label = getAppSubLabel();
+            }
+
+            if (label == null) {
+                label = (String) mAi.loadLabel(mPm);
+            }
+
+            return label;
+        }
+
+        String getSubLabel() {
+            // Apps with the substitute permission will never have a sublabel
+            if (mHasSubstitutePermission) return null;
+            return getAppSubLabel();
+        }
+
+        @Nullable
+        protected Drawable loadIconFromResource(Resources res, int resId) {
+            return res.getDrawableForDensity(resId, mIconDpi);
+        }
+
+    }
+
+    protected class ResolveInfoPresentationGetter extends TargetPresentationGetter {
+
+        private final ResolveInfo mRi;
+
+        ResolveInfoPresentationGetter(ResolveInfo ri) {
+            super(ri.activityInfo.applicationInfo);
+            mRi = ri;
+        }
+
+        @Override
+        Drawable getIconSubstitute() {
+            Drawable dr = null;
+            try {
+                // Do not use ResolveInfo#getIconResource() as it defaults to the app
+                if (mRi.resolvePackageName != null && mRi.icon != 0) {
+                    dr = loadIconFromResource(
+                            mPm.getResourcesForApplication(mRi.resolvePackageName), mRi.icon);
                 }
             } catch (NameNotFoundException e) {
                 Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
                         + "couldn't find resources for package", e);
             }
+
+            return dr;
         }
 
-        // Use app icons for better user association
-        if (dr == null) {
+        @Override
+        String getAppSubLabel() {
+            return (String) mRi.loadLabel(mPm);
+        }
+    }
+
+    protected class ActivityInfoPresentationGetter extends TargetPresentationGetter {
+        private final ActivityInfo mActivityInfo;
+        protected ActivityInfoPresentationGetter(ActivityInfo activityInfo) {
+            super(activityInfo.applicationInfo);
+            mActivityInfo = activityInfo;
+        }
+
+        @Override
+        Drawable getIconSubstitute() {
+            Drawable dr = null;
             try {
-                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.applicationInfo),
-                        ri.activityInfo.applicationInfo.icon);
-            } catch (NameNotFoundException ignore) {
+                // Do not use ActivityInfo#getIconResource() as it defaults to the app
+                if (mActivityInfo.icon != 0) {
+                    dr = loadIconFromResource(
+                            mPm.getResourcesForApplication(mActivityInfo.applicationInfo),
+                            mActivityInfo.icon);
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
+                        + "couldn't find resources for package", e);
             }
+
+            return dr;
         }
 
-        // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
-        if (dr == null) {
-            dr = ri.activityInfo.applicationInfo.loadIcon(mPm);
+        @Override
+        String getAppSubLabel() {
+            return (String) mActivityInfo.loadLabel(mPm);
         }
+    }
 
-        return new BitmapDrawable(this.getResources(),
-                mSimpleIconFactory.createUserBadgedIconBitmap(dr, Process.myUserHandle()));
+    Drawable loadIconForResolveInfo(ResolveInfo ri) {
+        return (new ResolveInfoPresentationGetter(ri)).getIcon();
     }
 
     @Override
@@ -1250,33 +1329,6 @@
             return mDisplayIcon;
         }
 
-        public Drawable getBadgeIcon() {
-            // We only expose a badge if we have extended info.
-            // The badge is a higher-priority disambiguation signal
-            // but we don't need one if we wouldn't show extended info at all.
-            if (TextUtils.isEmpty(getExtendedInfo())) {
-                return null;
-            }
-
-            if (mBadge == null && mResolveInfo != null && mResolveInfo.activityInfo != null
-                    && mResolveInfo.activityInfo.applicationInfo != null) {
-                if (mResolveInfo.activityInfo.icon == 0 || mResolveInfo.activityInfo.icon
-                        == mResolveInfo.activityInfo.applicationInfo.icon) {
-                    // Badging an icon with exactly the same icon is silly.
-                    // If the activityInfo icon resid is 0 it will fall back
-                    // to the application's icon, making it a match.
-                    return null;
-                }
-                mBadge = mResolveInfo.activityInfo.applicationInfo.loadIcon(mPm);
-            }
-            return mBadge;
-        }
-
-        @Override
-        public CharSequence getBadgeContentDescription() {
-            return null;
-        }
-
         @Override
         public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
             return new DisplayResolveInfo(this, fillInIntent, flags);
@@ -1413,21 +1465,11 @@
         CharSequence getExtendedInfo();
 
         /**
-         * @return The drawable that should be used to represent this target
+         * @return The drawable that should be used to represent this target including badge
          */
         Drawable getDisplayIcon();
 
         /**
-         * @return The (small) icon to badge the target with
-         */
-        Drawable getBadgeIcon();
-
-        /**
-         * @return The content description for the badge icon
-         */
-        CharSequence getBadgeContentDescription();
-
-        /**
          * Clone this target with the given fill-in information.
          */
         TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
@@ -1963,16 +2005,6 @@
                 new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
             }
             holder.icon.setImageDrawable(info.getDisplayIcon());
-            if (holder.badge != null) {
-                final Drawable badge = info.getBadgeIcon();
-                if (badge != null) {
-                    holder.badge.setImageDrawable(badge);
-                    holder.badge.setContentDescription(info.getBadgeContentDescription());
-                    holder.badge.setVisibility(View.VISIBLE);
-                } else {
-                    holder.badge.setVisibility(View.GONE);
-                }
-            }
         }
     }
 
@@ -2027,13 +2059,11 @@
         public TextView text;
         public TextView text2;
         public ImageView icon;
-        public ImageView badge;
 
         public ViewHolder(View view) {
             text = (TextView) view.findViewById(com.android.internal.R.id.text1);
             text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
             icon = (ImageView) view.findViewById(R.id.icon);
-            badge = (ImageView) view.findViewById(R.id.target_badge);
         }
     }
 
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index f48102a..156baf0 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -55,7 +55,7 @@
     private static final String TAG = "ResolverListController";
     private static final boolean DEBUG = false;
 
-    private ResolverComparator mResolverComparator;
+    private AbstractResolverComparator mResolverComparator;
     private boolean isComputed = false;
 
     public ResolverListController(
@@ -70,7 +70,8 @@
         mTargetIntent = targetIntent;
         mReferrerPackage = referrerPackage;
         mResolverComparator =
-                new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
+                new ResolverRankerServiceResolverComparator(
+                    mContext, mTargetIntent, mReferrerPackage, null);
     }
 
     @VisibleForTesting
@@ -221,7 +222,7 @@
         return listToReturn;
     }
 
-    private class ComputeCallback implements ResolverComparator.AfterCompute {
+    private class ComputeCallback implements AbstractResolverComparator.AfterCompute {
 
         private CountDownLatch mFinishComputeSignal;
 
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
similarity index 96%
rename from core/java/com/android/internal/app/ResolverComparator.java
rename to core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
index b9f67e6..a88a80f 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
@@ -46,7 +46,6 @@
 
 import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -54,10 +53,10 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * Ranks and compares packages based on usage stats.
+ * Ranks and compares packages based on usage stats and uses the {@link ResolverRankerService}.
  */
-class ResolverComparator implements Comparator<ResolvedComponentInfo> {
-    private static final String TAG = "ResolverComparator";
+class ResolverRankerServiceResolverComparator extends AbstractResolverComparator {
+    private static final String TAG = "RRSResolverComparator";
 
     private static final boolean DEBUG = false;
 
@@ -100,7 +99,6 @@
     private ComponentName mRankerServiceName;
     private IResolverRankerService mRanker;
     private ResolverRankerServiceConnection mConnection;
-    private AfterCompute mAfterCompute;
     private Context mContext;
     private CountDownLatch mConnectSignal;
 
@@ -155,12 +153,8 @@
         }
     };
 
-    public interface AfterCompute {
-        public void afterCompute ();
-    }
-
-    public ResolverComparator(Context context, Intent intent, String referrerPackage,
-                              AfterCompute afterCompute) {
+    public ResolverRankerServiceResolverComparator(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);
@@ -185,7 +179,7 @@
     }
 
     // get annotations of content from intent.
-    public void getContentAnnotations(Intent intent) {
+    private void getContentAnnotations(Intent intent) {
         ArrayList<String> annotations = intent.getStringArrayListExtra(
                 Intent.EXTRA_CONTENT_ANNOTATIONS);
         if (annotations != null) {
@@ -200,11 +194,8 @@
         }
     }
 
-    public void setCallBack(AfterCompute afterCompute) {
-        mAfterCompute = afterCompute;
-    }
-
     // compute features for each target according to usage stats of targets.
+    @Override
     public void compute(List<ResolvedComponentInfo> targets) {
         reset();
 
@@ -349,6 +340,7 @@
         return mCollator.compare(sa.toString().trim(), sb.toString().trim());
     }
 
+    @Override
     public float getScore(ComponentName name) {
         final ResolverTarget target = mTargetsDict.get(name);
         if (target != null) {
@@ -357,6 +349,7 @@
         return 0;
     }
 
+    @Override
     public void updateChooserCounts(String packageName, int userId, String action) {
         if (mUsm != null) {
             mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
@@ -364,6 +357,7 @@
     }
 
     // update ranking model when the connection to it is valid.
+    @Override
     public void updateModel(ComponentName componentName) {
         synchronized (mLock) {
             if (mRanker != null) {
@@ -397,6 +391,7 @@
     }
 
     // unbind the service and clear unhandled messges.
+    @Override
     public void destroy() {
         mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
         mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
@@ -478,8 +473,8 @@
                 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=\""
+                            + " - this service will not be queried for "
+                            + "ResolverRankerServiceResolverComparator. add android:permission=\""
                             + ResolverRankerService.BIND_PERMISSION + "\""
                             + " to the <service> tag for " + componentName
                             + " in the manifest.");
@@ -490,7 +485,8 @@
                         resolveInfo.serviceInfo.packageName)) {
                     Log.w(TAG, "ResolverRankerService " + componentName + " does not hold"
                             + " permission " + ResolverRankerService.HOLD_PERMISSION
-                            + " - this service will not be queried for ResolverComparator.");
+                            + " - this service will not be queried for "
+                            + "ResolverRankerServiceResolverComparator.");
                     continue;
                 }
             } catch (NameNotFoundException e) {
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index eb1530e..a85485d 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -16,11 +16,13 @@
 
 package com.android.internal.app;
 
+import static android.content.Context.ACTIVITY_SERVICE;
 import static android.graphics.Paint.DITHER_FLAG;
 import static android.graphics.Paint.FILTER_BITMAP_FLAG;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -42,6 +44,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.AttributeSet;
+import android.util.Pools.SynchronizedPool;
 
 import com.android.internal.R;
 
@@ -58,6 +61,9 @@
 @Deprecated
 public class SimpleIconFactory {
 
+    private static final SynchronizedPool<SimpleIconFactory> sPool =
+            new SynchronizedPool<>(Runtime.getRuntime().availableProcessors());
+
     private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
     private static final float BLUR_FACTOR = 0.5f / 48;
 
@@ -74,10 +80,45 @@
     private final Rect mOldBounds = new Rect();
 
     /**
+     * Obtain a SimpleIconFactory from a pool objects.
+     *
      * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
      */
     @Deprecated
-    SimpleIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
+    public static SimpleIconFactory obtain(Context ctx) {
+        SimpleIconFactory instance = sPool.acquire();
+        if (instance == null) {
+            final ActivityManager am = (ActivityManager) ctx.getSystemService(ACTIVITY_SERVICE);
+            final int iconDpi = (am == null) ? 0 : am.getLauncherLargeIconDensity();
+
+            final Resources r = ctx.getResources();
+            final int iconSize = r.getDimensionPixelSize(R.dimen.resolver_icon_size);
+            final int badgeSize = r.getDimensionPixelSize(R.dimen.resolver_badge_size);
+
+            instance = new SimpleIconFactory(ctx, iconDpi, iconSize, badgeSize);
+            instance.setWrapperBackgroundColor(Color.WHITE);
+        }
+
+        return instance;
+    }
+
+    /**
+     * Recycles the SimpleIconFactory so others may use it.
+     *
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    public void recycle() {
+        // Return to default background color
+        setWrapperBackgroundColor(Color.WHITE);
+        sPool.release(this);
+    }
+
+    /**
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    private SimpleIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
             int badgeBitmapSize) {
         mContext = context.getApplicationContext();
         mPm = mContext.getPackageManager();
@@ -170,7 +211,7 @@
      * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
      */
     @Deprecated
-    public Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
+    Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
         // Flatten the passed in icon
         float [] scale = new float[1];
 
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 5c144d3..0a83fcc 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -481,7 +481,11 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "[" + mComponentName + "]";
+        return getClass().getSimpleName() + "[" + mComponentName
+                + " " + System.identityHashCode(this)
+                + (mService != null ? " (bound)" : " (unbound)")
+                + (mDestroyed ? " (destroyed)" : "")
+                + "]";
     }
 
     /**
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index c4626c2..b3cfa49 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -218,7 +218,7 @@
     private boolean mLastHasRightStableInset = false;
     private boolean mLastHasLeftStableInset = false;
     private int mLastWindowFlags = 0;
-    private boolean mLastShouldAlwaysConsumeNavBar = false;
+    private boolean mLastShouldAlwaysConsumeSystemBars = false;
 
     private int mRootScrollY = 0;
 
@@ -1102,7 +1102,7 @@
                 disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
                 mLastHasLeftStableInset = hasLeftStableInset;
 
-                mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar();
+                mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
             }
 
             boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
@@ -1133,7 +1133,7 @@
                 (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
-                || mLastShouldAlwaysConsumeNavBar;
+                || mLastShouldAlwaysConsumeSystemBars;
 
         // If we didn't request fullscreen layout, but we still got it because of the
         // mForceWindowDrawsStatusBarBackground flag, also consume top inset.
@@ -1142,7 +1142,8 @@
                 && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
                 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
                 && mForceWindowDrawsStatusBarBackground
-                && mLastTopInset != 0;
+                && mLastTopInset != 0
+                || mLastShouldAlwaysConsumeSystemBars;
 
         int consumedTop = consumingStatusBar ? mLastTopInset : 0;
         int consumedRight = consumingNavBar ? mLastRightInset : 0;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ae5c67d..fb9ff15 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -44,7 +44,7 @@
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
             Rect stableInsets, Rect outsets, boolean reportDraw,
             MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-            boolean alwaysConsumeNavBar, int displayId,
+            boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) {
         if (reportDraw) {
             try {
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 41e2fc8..b36c3fa 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -42,7 +42,7 @@
     long getLong(in String key, in long defaultValue, in int userId);
     @UnsupportedAppUsage
     String getString(in String key, in String defaultValue, in int userId);
-    void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
+    void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange);
     void resetKeyStore(int userId);
     VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
             in ICheckCredentialProgressCallback progressCallback);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1965609..dd48c15 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -78,7 +78,6 @@
 public class LockPatternUtils {
 
     private static final String TAG = "LockPatternUtils";
-    private static final boolean DEBUG = false;
     private static final boolean FRP_CREDENTIAL_ENABLED = true;
 
     /**
@@ -87,12 +86,6 @@
     public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
 
     /**
-     * The number of incorrect attempts before which we fall back on an alternative
-     * method of verifying the user, and resetting their lock pattern.
-     */
-    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
-
-    /**
      * The interval of the countdown for showing progress of the lockout.
      */
     public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
@@ -115,18 +108,23 @@
     public static final int MIN_LOCK_PASSWORD_SIZE = 4;
 
     /**
-     * The minimum number of dots the user must include in a wrong pattern
-     * attempt for it to be counted against the counts that affect
-     * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
+     * The minimum number of dots the user must include in a wrong pattern attempt for it to be
+     * counted.
      */
     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
 
     public static final int CREDENTIAL_TYPE_NONE = -1;
-
     public static final int CREDENTIAL_TYPE_PATTERN = 1;
-
     public static final int CREDENTIAL_TYPE_PASSWORD = 2;
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CREDENTIAL_TYPE_"}, value = {
+            CREDENTIAL_TYPE_NONE,
+            CREDENTIAL_TYPE_PATTERN,
+            CREDENTIAL_TYPE_PASSWORD, // Either pin or password.
+    })
+    public @interface CredentialType {}
+
     /**
      * Special user id for triggering the FRP verification flow.
      */
@@ -671,17 +669,25 @@
     /**
      * Clear any lock pattern or password.
      */
-    public void clearLock(byte[] savedCredential, int userHandle) {
+    public boolean clearLock(byte[] savedCredential, int userHandle) {
+        return clearLock(savedCredential, userHandle, false);
+    }
+
+    /**
+     * Clear any lock pattern or password, with the option to ignore incorrect existing credential.
+     */
+    public boolean clearLock(byte[] savedCredential, int userHandle, boolean allowUntrustedChange) {
         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
 
         try{
             getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
-                    savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
+                    savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle,
+                    allowUntrustedChange);
         } catch (Exception e) {
             Log.e(TAG, "Failed to clear lock", e);
             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
-            return;
+            return false;
         }
 
         if (userHandle == UserHandle.USER_SYSTEM) {
@@ -691,6 +697,7 @@
         }
 
         onAfterChangingPassword(userHandle);
+        return true;
     }
 
     /**
@@ -728,19 +735,28 @@
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
+     * @param savedPattern The previously saved pattern, converted to byte[] format
      * @param userId the user whose pattern is to be saved.
+     *
+     * @return whether this was successful or not.
      */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
-        this.saveLockPattern(pattern, null, userId);
+    public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
+            int userId) {
+        return saveLockPattern(pattern, savedPattern, userId, false);
     }
+
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
      * @param savedPattern The previously saved pattern, converted to byte[] format
      * @param userId the user whose pattern is to be saved.
+     * @param allowUntrustedChange whether we want to allow saving a new password if the existing
+     * password being provided is incorrect.
+     *
+     * @return whether this was successful or not.
      */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
-            int userId) {
+    public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
+            int userId, boolean allowUntrustedChange) {
         if (!hasSecureLockScreen()) {
             throw new UnsupportedOperationException(
                     "This operation requires the lock screen feature.");
@@ -755,11 +771,11 @@
         setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
         try {
             getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
-                    PASSWORD_QUALITY_SOMETHING, userId);
+                    PASSWORD_QUALITY_SOMETHING, userId, allowUntrustedChange);
         } catch (Exception e) {
             Log.e(TAG, "Couldn't save lock pattern", e);
             setKeyguardStoredPasswordQuality(currentQuality, userId);
-            return;
+            return false;
         }
         // Update the device encryption password.
         if (userId == UserHandle.USER_SYSTEM
@@ -773,6 +789,7 @@
 
         reportPatternWasChosen(userId);
         onAfterChangingPassword(userId);
+        return true;
     }
 
     private void updateCryptoUserInfo(int userId) {
@@ -875,17 +892,20 @@
      * password.
      * @param password The password to save
      * @param savedPassword The previously saved lock password, or null if none
-     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
+     * android.content.ComponentName)}
      * @param userHandle The userId of the user to change the password for
      *
+     * @return whether this was successful or not.
+     *
      * @deprecated Pass password as a byte array
      */
     @Deprecated
-    public void saveLockPassword(String password, String savedPassword, int requestedQuality,
+    public boolean saveLockPassword(String password, String savedPassword, int requestedQuality,
             int userHandle) {
         byte[] passwordBytes = password != null ? password.getBytes() : null;
         byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
-        saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
+        return saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
     }
 
     /**
@@ -895,11 +915,34 @@
      * @param password The password to save
      * @param savedPassword The previously saved lock password, or null if none
      * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
-     *          android.content.ComponentName)}
+     * android.content.ComponentName)}
      * @param userHandle The userId of the user to change the password for
+     *
+     * @return whether this was successful or not.
      */
-    public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
+    public boolean saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
             int userHandle) {
+        return saveLockPassword(password, savedPassword, requestedQuality,
+                userHandle, false);
+    }
+
+    /**
+     * Save a lock password.  Does not ensure that the password is as good
+     * as the requested mode, but will adjust the mode to be as good as the
+     * password.
+     * @param password The password to save
+     * @param savedPassword The previously saved lock password, or null if none
+     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
+     * android.content.ComponentName)}
+     * @param userHandle The userId of the user to change the password for
+     * @param allowUntrustedChange whether we want to allow saving a new password if the existing
+     * password being provided is incorrect.
+     *
+     * @return whether this method saved the new password successfully or not. This flow will fail
+     * and return false if the given credential is wrong and allowUntrustedChange is false.
+     */
+    public boolean saveLockPassword(byte[] password, byte[] savedPassword,
+            int requestedQuality, int userHandle, boolean allowUntrustedChange) {
         if (!hasSecureLockScreen()) {
             throw new UnsupportedOperationException(
                     "This operation requires the lock screen feature.");
@@ -915,22 +958,36 @@
         }
 
         final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
-        setKeyguardStoredPasswordQuality(
-                computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
-                userHandle);
+        final int passwordQuality = PasswordMetrics.computeForPassword(password).quality;
+        final int newKeyguardQuality =
+                computeKeyguardQuality(CREDENTIAL_TYPE_PASSWORD, requestedQuality, passwordQuality);
+        setKeyguardStoredPasswordQuality(newKeyguardQuality, userHandle);
         try {
             getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
-                    requestedQuality, userHandle);
+                    requestedQuality, userHandle, allowUntrustedChange);
         } catch (Exception e) {
             Log.e(TAG, "Unable to save lock password", e);
             setKeyguardStoredPasswordQuality(currentQuality, userHandle);
-            return;
+            return false;
         }
 
-        updateEncryptionPasswordIfNeeded(password,
-                PasswordMetrics.computeForPassword(password).quality, userHandle);
+        updateEncryptionPasswordIfNeeded(password, passwordQuality, userHandle);
         updatePasswordHistory(password, userHandle);
         onAfterChangingPassword(userHandle);
+        return true;
+    }
+
+    /**
+     * Compute keyguard credential quality to store in PASSWORD_TYPE_KEY by computing max between
+     * them so that digit-only password is distinguished from PIN.
+     *
+     * TODO: remove this method and make CREDENTIAL_TYPE distinguish between PIN and password, so
+     * that this quality is no longer needs to be persisted.
+     */
+    private int computeKeyguardQuality(
+            @CredentialType int credentialType, int requestedQuality, int passwordQuality) {
+        return credentialType == CREDENTIAL_TYPE_PASSWORD
+                ? Math.max(passwordQuality, requestedQuality) : passwordQuality;
     }
 
     /**
@@ -1033,24 +1090,6 @@
     }
 
     /**
-     * Returns the password quality of the given credential, promoting it to a higher level
-     * if DevicePolicyManager has a stronger quality requirement. This value will be written
-     * to PASSWORD_TYPE_KEY.
-     */
-    private int computePasswordQuality(int type, byte[] credential, int requestedQuality) {
-        final int quality;
-        if (type == CREDENTIAL_TYPE_PASSWORD) {
-            int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
-            quality = Math.max(requestedQuality, computedQuality);
-        } else if (type == CREDENTIAL_TYPE_PATTERN)  {
-            quality = PASSWORD_QUALITY_SOMETHING;
-        } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
-            quality = PASSWORD_QUALITY_UNSPECIFIED;
-        }
-        return quality;
-    }
-
-    /**
      * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
      * for user handles that do not belong to a managed profile.
      *
@@ -1752,9 +1791,10 @@
                 throw new IllegalArgumentException("password must not be null and at least "
                         + "of length " + MIN_LOCK_PASSWORD_SIZE);
             }
-            final int quality = computePasswordQuality(type, credential, requestedQuality);
+            final int quality = PasswordMetrics.computeForCredential(type, credential).quality;
+            final int keyguardQuality = computeKeyguardQuality(type, quality, requestedQuality);
             if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token,
-                    quality, userId)) {
+                    keyguardQuality, userId)) {
                 return false;
             }
             setKeyguardStoredPasswordQuality(quality, userId);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index cd34d2e..664f7f4 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,10 +1,10 @@
 
 genrule {
-    name: "android_util_StatsLog.cpp",
+    name: "android_util_StatsLogInternal.cpp",
     tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLog.cpp",
+    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp",
     out: [
-        "android_util_StatsLog.cpp",
+        "android_util_StatsLogInternal.cpp",
     ],
 }
 
@@ -111,6 +111,7 @@
         "android_util_Binder.cpp",
         "android_util_EventLog.cpp",
         "android_util_Log.cpp",
+        "android_util_StatsLog.cpp",
         "android_util_MemoryIntArray.cpp",
         "android_util_PathParser.cpp",
         "android_util_Process.cpp",
@@ -306,7 +307,7 @@
         "server_configurable_flags",
     ],
 
-    generated_sources: ["android_util_StatsLog.cpp"],
+    generated_sources: ["android_util_StatsLogInternal.cpp"],
 
     local_include_dirs: ["android/graphics"],
     export_include_dirs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 20bed1b..ccd0b66 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,6 +127,7 @@
 extern int register_android_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_StatsLog(JNIEnv* env);
+extern int register_android_util_StatsLogInternal(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
 extern int register_android_util_PathParser(JNIEnv* env);
@@ -1400,6 +1401,7 @@
     REG_JNI(register_android_util_MemoryIntArray),
     REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_util_StatsLog),
+    REG_JNI(register_android_util_StatsLogInternal),
     REG_JNI(register_android_app_admin_SecurityLog),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 02dffdc2..342aba0 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -821,18 +821,18 @@
     return jStatus;
 }
 
-static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz,
-                                                              jint direction) {
+static int android_media_AudioRecord_set_preferred_microphone_direction(
+                                JNIEnv *env, jobject thiz, jint direction) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()");
+            "Unable to retrieve AudioRecord pointer for setPreferredMicrophoneDirection()");
         return (jint)AUDIO_JAVA_ERROR;
     }
 
     jint jStatus = AUDIO_JAVA_SUCCESS;
-    status_t status =
-        lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+    status_t status = lpRecorder->setPreferredMicrophoneDirection(
+                            static_cast<audio_microphone_direction_t>(direction));
     if (status != NO_ERROR) {
         jStatus = nativeToJavaStatus(status);
     }
@@ -840,17 +840,17 @@
     return jStatus;
 }
 
-static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz,
-                                                                    jfloat zoom) {
+static int android_media_AudioRecord_set_preferred_microphone_field_dimension(
+                                JNIEnv *env, jobject thiz, jfloat zoom) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()");
+            "Unable to retrieve AudioRecord pointer for setPreferredMicrophoneFieldDimension()");
         return (jint)AUDIO_JAVA_ERROR;
     }
 
     jint jStatus = AUDIO_JAVA_SUCCESS;
-    status_t status = lpRecorder->setMicrophoneFieldDimension(zoom);
+    status_t status = lpRecorder->setPreferredMicrophoneFieldDimension(zoom);
     if (status != NO_ERROR) {
         jStatus = nativeToJavaStatus(status);
     }
@@ -913,10 +913,10 @@
     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
                                         (void *)android_media_AudioRecord_get_active_microphones},
     {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
-    {"native_set_microphone_direction", "(I)I",
-                                (void *)android_media_AudioRecord_set_microphone_direction},
-    {"native_set_microphone_field_dimension", "(F)I",
-                                (void *)android_media_AudioRecord_set_microphone_field_dimension},
+    {"native_set_preferred_microphone_direction", "(I)I",
+                        (void *)android_media_AudioRecord_set_preferred_microphone_direction},
+    {"native_set_preferred_microphone_field_dimension", "(F)I",
+                        (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 1a90ebf..c8f81e2 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2038,13 +2038,13 @@
 
 static jboolean
 android_media_AudioSystem_isOffloadSupported(JNIEnv *env, jobject thiz,
-        jint encoding, jint sampleRate, jint channelMask, jint channelIndexMask)
+        jint encoding, jint sampleRate, jint channelMask, jint channelIndexMask, jint streamType)
 {
     audio_offload_info_t format = AUDIO_INFO_INITIALIZER;
     format.format = (audio_format_t) audioFormatToNative(encoding);
     format.sample_rate = (uint32_t) sampleRate;
     format.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
-    format.stream_type = AUDIO_STREAM_MUSIC;
+    format.stream_type = (audio_stream_type_t) streamType;
     format.has_video = false;
     format.is_streaming = false;
     // offload duration unknown at this point:
@@ -2292,7 +2292,7 @@
                                     (void *)android_media_AudioSystem_registerRecordingCallback},
     {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
     {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
-    {"native_is_offload_supported", "(IIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
+    {"native_is_offload_supported", "(IIIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
     {"getMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_getMicrophones},
     {"getSurroundFormats", "(Ljava/util/Map;Z)I", (void *)android_media_AudioSystem_getSurroundFormats},
     {"setSurroundFormatEnabled", "(IZ)I", (void *)android_media_AudioSystem_setSurroundFormatEnabled},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index cfb2dd1..d7a981e 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -487,6 +487,11 @@
     return answer;
 }
 
+static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    resNetworkCancel(fd);
+}
+
 static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
     if (javaFd == NULL) {
         jniThrowNullPointerException(env, NULL);
@@ -546,6 +551,7 @@
     { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
     { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
     { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult },
+    { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
new file mode 100644
index 0000000..e749d34
--- /dev/null
+++ b/core/jni/android_util_StatsLog.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_NAMESPACE "StatsLog.tag."
+#define LOG_TAG "StatsLog_println"
+
+#include <assert.h>
+#include <cutils/properties.h>
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "utils/misc.h"
+#include "core_jni_helpers.h"
+#include "stats_event_list.h"
+
+namespace android {
+
+static void android_util_StatsLog_writeRaw(JNIEnv* env, jobject clazz, jbyteArray buf, jint size)
+{
+    if (buf == NULL) {
+        return;
+    }
+    jint actualSize = env->GetArrayLength(buf);
+    if (actualSize < size) {
+        return;
+    }
+
+    jbyte* bufferArray = env->GetByteArrayElements(buf, NULL);
+    if (bufferArray == NULL) {
+        return;
+    }
+    const uint32_t statsEventTag = 1937006964;
+    struct iovec vec[2];
+    vec[0].iov_base = (void*) &statsEventTag;
+    vec[0].iov_len = sizeof(statsEventTag);
+    vec[1].iov_base = (void*) bufferArray;
+    vec[1].iov_len = size;
+    write_to_statsd(vec, 2);
+
+    env->ReleaseByteArrayElements(buf, bufferArray, 0);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "writeRaw", "([BI)V", (void*) android_util_StatsLog_writeRaw },
+};
+
+int register_android_util_StatsLog(JNIEnv* env)
+{
+    return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 4a6c72b..94f96ba 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -126,6 +126,41 @@
     jfieldID white;
 } gDisplayPrimariesClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID builder;
+} gScreenshotGraphicBufferClassInfo;
+
+class JNamedColorSpace {
+public:
+    // ColorSpace.Named.SRGB.ordinal() = 0;
+    static constexpr jint SRGB = 0;
+
+    // ColorSpace.Named.DISPLAY_P3.ordinal() = 6;
+    static constexpr jint DISPLAY_P3 = 6;
+};
+
+constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
+    switch (dataspace) {
+        case ui::Dataspace::DISPLAY_P3:
+            return JNamedColorSpace::DISPLAY_P3;
+        default:
+            return JNamedColorSpace::SRGB;
+    }
+}
+
+constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
+    switch (colorMode) {
+        case ui::ColorMode::DISPLAY_P3:
+        case ui::ColorMode::BT2100_PQ:
+        case ui::ColorMode::BT2100_HLG:
+        case ui::ColorMode::DISPLAY_BT2020:
+            return ui::Dataspace::DISPLAY_P3;
+        default:
+            return ui::Dataspace::V0_SRGB;
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -210,9 +245,12 @@
     if (displayToken == NULL) {
         return NULL;
     }
+    const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
+    const ui::Dataspace dataspace = pickDataspaceFromColorMode(colorMode);
+
     Rect sourceCrop = rectFromObj(env, sourceCropObj);
     sp<GraphicBuffer> buffer;
-    status_t res = ScreenshotClient::capture(displayToken, ui::Dataspace::V0_SRGB,
+    status_t res = ScreenshotClient::capture(displayToken, dataspace,
             ui::PixelFormat::RGBA_8888,
             sourceCrop, width, height,
             useIdentityTransform, rotation, captureSecureLayers, &buffer);
@@ -220,13 +258,15 @@
         return NULL;
     }
 
-    return env->CallStaticObjectMethod(gGraphicBufferClassInfo.clazz,
-            gGraphicBufferClassInfo.builder,
+    const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+    return env->CallStaticObjectMethod(gScreenshotGraphicBufferClassInfo.clazz,
+            gScreenshotGraphicBufferClassInfo.builder,
             buffer->getWidth(),
             buffer->getHeight(),
             buffer->getPixelFormat(),
             (jint)buffer->getUsage(),
-            (jlong)buffer.get());
+            (jlong)buffer.get(),
+            namedColorSpace);
 }
 
 static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
@@ -243,20 +283,23 @@
     }
 
     sp<GraphicBuffer> buffer;
-    status_t res = ScreenshotClient::captureChildLayers(layerHandle, ui::Dataspace::V0_SRGB,
+    const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB;
+    status_t res = ScreenshotClient::captureChildLayers(layerHandle, dataspace,
                                                         ui::PixelFormat::RGBA_8888, sourceCrop,
                                                         frameScale, &buffer);
     if (res != NO_ERROR) {
         return NULL;
     }
 
-    return env->CallStaticObjectMethod(gGraphicBufferClassInfo.clazz,
-                                       gGraphicBufferClassInfo.builder,
+    const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+    return env->CallStaticObjectMethod(gScreenshotGraphicBufferClassInfo.clazz,
+                                       gScreenshotGraphicBufferClassInfo.builder,
                                        buffer->getWidth(),
                                        buffer->getHeight(),
                                        buffer->getPixelFormat(),
                                        (jint)buffer->getUsage(),
-                                       (jlong)buffer.get());
+                                       (jlong)buffer.get(),
+                                       namedColorSpace);
 }
 
 static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -1306,9 +1349,13 @@
             (void*)nativeSetOverrideScalingMode },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
             (void*)nativeGetHandle },
-    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)Landroid/graphics/GraphicBuffer;",
+    {"nativeScreenshot",
+            "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)"
+            "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
             (void*)nativeScreenshot },
-    {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
+    {"nativeCaptureLayers",
+            "(Landroid/os/IBinder;Landroid/graphics/Rect;F)"
+            "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
             (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
             (void*)nativeSetInputWindowInfo },
@@ -1386,6 +1433,14 @@
     gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz,
             "createFromExisting", "(IIIIJ)Landroid/graphics/GraphicBuffer;");
 
+    jclass screenshotGraphicsBufferClazz = FindClassOrDie(env,
+            "android/view/SurfaceControl$ScreenshotGraphicBuffer");
+    gScreenshotGraphicBufferClassInfo.clazz =
+            MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
+    gScreenshotGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env,
+            screenshotGraphicsBufferClazz,
+            "createFromNative", "(IIIIJI)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;");
+
     jclass displayedContentSampleClazz = FindClassOrDie(env,
             "android/hardware/display/DisplayedContentSample");
     gDisplayedContentSampleClassInfo.clazz = MakeGlobalRefOrDie(env, displayedContentSampleClazz);
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 25caafb..b4be3f5 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2316,4 +2316,7 @@
     // OPEN: Settings > Face > Remove face
     // OS: Q
     DIALOG_FACE_REMOVE = 1693;
+
+    // Settings > Display > Theme
+    DARK_UI_SETTINGS = 1698;
 }
diff --git a/core/proto/android/stats/connectivity/Android.bp b/core/proto/android/stats/connectivity/Android.bp
new file mode 100644
index 0000000..5aa4ddb
--- /dev/null
+++ b/core/proto/android/stats/connectivity/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 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.
+
+java_library_static {
+    name: "networkstackprotosnano",
+    proto: {
+        type: "nano",
+    },
+    srcs: [
+        "network_stack.proto",
+    ],
+    sdk_version: "system_current",
+    no_framework_libs: true,
+}
\ No newline at end of file
diff --git a/core/proto/android/stats/connectivity/network_stack.proto b/core/proto/android/stats/connectivity/network_stack.proto
new file mode 100644
index 0000000..7d9aa1c
--- /dev/null
+++ b/core/proto/android/stats/connectivity/network_stack.proto
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+syntax = "proto2";
+
+package android.stats.connectivity;
+option java_multiple_files = true;
+option java_outer_classname = "NetworkStackProto";
+
+message NetworkStackEventData {
+
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5427147..cb8ece7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1849,8 +1849,8 @@
     <permission android:name="android.permission.HARDWARE_TEST"
         android:protectionLevel="signature" />
 
-    <!-- @hide Allows an application to manage DynamicAndroid image -->
-    <permission android:name="android.permission.MANAGE_DYNAMIC_ANDROID"
+    <!-- @hide Allows an application to manage DynamicSystem image -->
+    <permission android:name="android.permission.MANAGE_DYNAMIC_SYSTEM"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows access to Broadcast Radio
@@ -1989,6 +1989,12 @@
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows the app to request network scans from telephony.
+         <p>Not for use by third-party applications.
+         @SystemApi @hide-->
+    <permission android:name="android.permission.NETWORK_SCAN"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a link {@link android.telephony.VisualVoicemailService} to ensure that
          only the system can bind to it.
          <p>Protection level: signature|privileged
@@ -3927,7 +3933,7 @@
     <permission android:name="android.permission.MANAGE_ROLLBACKS"
         android:protectionLevel="signature|verifier" />
 
-    <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. -->
+    <!-- @TestApi @hide Allows testing apk level rollbacks. -->
     <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
         android:protectionLevel="signature" />
 
@@ -4484,6 +4490,11 @@
     <permission android:name="android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to access shared libraries.
+         @hide -->
+    <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
+                android:protectionLevel="signature|installer" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/drawable-car/car_dialog_button_background.xml b/core/res/res/drawable-car/car_dialog_button_background.xml
index dc742d5..67506cb 100644
--- a/core/res/res/drawable-car/car_dialog_button_background.xml
+++ b/core/res/res/drawable-car/car_dialog_button_background.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License.
   -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        android:color="@*android:color/car_card_ripple_background">
+        android:color="?android:attr/colorControlHighlight">
     <item android:id="@android:id/mask">
         <color android:color="@*android:color/car_white_1000" />
     </item>
diff --git a/core/res/res/layout/chooser_row.xml b/core/res/res/layout/chooser_row.xml
index d4585eb..742d7eed 100644
--- a/core/res/res/layout/chooser_row.xml
+++ b/core/res/res/layout/chooser_row.xml
@@ -21,8 +21,8 @@
               android:layout_width="match_parent"
               android:layout_height="100dp"
               android:gravity="start|top"
-              android:paddingStart="@dimen/chooser_grid_padding"
-              android:paddingEnd="@dimen/chooser_grid_padding">
+              android:paddingStart="@dimen/chooser_edge_margin_normal"
+              android:paddingEnd="@dimen/chooser_edge_margin_normal">
   <TextView
       android:id="@+id/chooser_row_text_option"
       android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 71c153f..4a3dfba 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -18,7 +18,7 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:orientation="vertical"
-              android:layout_width="76dp"
+              android:layout_width="@dimen/chooser_target_width"
               android:layout_height="wrap_content"
               android:minHeight="100dp"
               android:gravity="center"
@@ -27,22 +27,13 @@
               android:focusable="true"
               android:background="?attr/selectableItemBackgroundBorderless">
 
-    <FrameLayout android:layout_width="wrap_content"
-                 android:layout_height="wrap_content">
-        <ImageView android:id="@+id/icon"
-                   android:layout_width="48dp"
-                   android:layout_height="48dp"
-                   android:layout_marginLeft="3dp"
-                   android:layout_marginRight="3dp"
-                   android:layout_marginBottom="3dp"
-                   android:scaleType="fitCenter" />
-        <ImageView android:id="@+id/target_badge"
-                   android:layout_width="16dp"
-                   android:layout_height="16dp"
-                   android:layout_gravity="end|bottom"
-                   android:visibility="gone"
-                   android:scaleType="fitCenter" />
-    </FrameLayout>
+    <ImageView android:id="@+id/icon"
+               android:layout_width="@dimen/resolver_icon_size"
+               android:layout_height="@dimen/resolver_icon_size"
+               android:layout_marginLeft="3dp"
+               android:layout_marginRight="3dp"
+               android:layout_marginBottom="3dp"
+               android:scaleType="fitCenter" />
 
     <!-- Activity name -->
     <TextView android:id="@android:id/text1"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index de02286..14202f2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -916,6 +916,11 @@
           case, this can be disabled (set to false). -->
     <bool name="config_enableCarDockHomeLaunch">true</bool>
 
+    <!-- Control whether to force the display of System UI Bars at all times regardless of
+         System Ui Flags. This can be useful in the Automotive case if there's a requirement for
+         a UI element to be on screen at all times. -->
+    <bool name="config_forceShowSystemBars">false</bool>
+
     <!-- HDMI behavior -->
 
     <!-- The number of degrees to rotate the display when the device has HDMI connected
@@ -3217,6 +3222,12 @@
          -->
     <integer name="config_navBarOpacityMode">0</integer>
 
+    <!-- Controls the navigation bar interaction mode:
+         0: 3 button mode (back, home, overview buttons)
+         1: 2 button mode (back, home buttons + swipe up for overview)
+         2: gestures only for back, home and overview -->
+    <integer name="config_navBarInteractionMode">0</integer>
+
     <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
          These values are in DPs and will be converted to pixel sizes internally. -->
     <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 7134eed..023fbad 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -578,7 +578,6 @@
     <dimen name="default_magnifier_horizontal_offset">0dp</dimen>
     <item type="dimen" format="float" name="default_magnifier_zoom">1.25</item>
 
-    <dimen name="chooser_grid_padding">0dp</dimen>
     <!-- Spacing around the background change frome service to non-service -->
     <dimen name="chooser_service_spacing">8dp</dimen>
 
@@ -725,4 +724,5 @@
     <dimen name="chooser_preview_width">-1px</dimen>
     <dimen name="resolver_icon_size">42dp</dimen>
     <dimen name="resolver_badge_size">18dp</dimen>
+    <dimen name="chooser_target_width">76dp</dimen>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 24fd3a8..79bf738 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -802,7 +802,7 @@
     <string name="permgrouprequest_visual">Allow
         &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos?</string>
     <!-- Subtitle of the message shown to the user when the apps requests permission to access photos and videos [CHAR LIMIT=150]-->
-    <string name="permgrouprequestdetail_visual">Locations and other people in your photos and videos can be identified by the app</string>
+    <string name="permgrouprequestdetail_visual">This includes any locations tagged in your photos and videos</string>
 
     <!-- Title for the capability of an accessibility service to retrieve window content. -->
     <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
@@ -1584,7 +1584,7 @@
     <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=50] -->
     <string name="face_error_hw_not_available">Face hardware not available.</string>
     <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
-    <string name="face_error_timeout">Face time out reached. Try again.</string>
+    <string name="face_error_timeout">Face timeout reached. Try again.</string>
     <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=50] -->
     <string name="face_error_no_space">Face can\u2019t be stored.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
@@ -1596,11 +1596,11 @@
     <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=50] -->
     <string name="face_error_lockout_permanent">Too many attempts. Facial authentication disabled.</string>
     <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
-    <string name="face_error_unable_to_process">Try again.</string>
+    <string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
     <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=50] -->
-    <string name="face_error_not_enrolled">No face enrolled.</string>
+    <string name="face_error_not_enrolled">You haven\u2019t set up face authentication.</string>
     <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] -->
-    <string name="face_error_hw_not_present">This device does not have a face authentication sensor.</string>
+    <string name="face_error_hw_not_present">Face authentication is not supported on this device.</string>
 
     <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
     <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
@@ -3283,18 +3283,36 @@
     <string name="dump_heap_notification"><xliff:g id="proc">%1$s</xliff:g> exceeded memory
         limit</string>
 
+    <!-- Notification text to tell the user that a heap dump that they initiated for a process is ready [CHAR LIMIT=NONE] -->
+    <string name="dump_heap_ready_notification">
+        <xliff:g id="proc" example="com.android.example">%1$s</xliff:g> heap dump ready</string>
+
     <!-- Notification details to tell the user that a process has exceeded its memory limit. -->
     <string name="dump_heap_notification_detail">Heap dump collected. Tap to share.</string>
 
     <!-- Title of dialog prompting the user to share a heap dump. -->
     <string name="dump_heap_title">Share heap dump?</string>
 
-    <!-- Text of dialog prompting the user to share a heap dump. -->
-    <string name="dump_heap_text">The process <xliff:g id="proc">%1$s</xliff:g> has exceeded
-        its process memory limit of <xliff:g id="size">%2$s</xliff:g>.  A heap dump is available
+    <!-- Text of dialog prompting the user to share a heap dump for an application [CHAR LIMIT=NONE] -->
+    <string name="dump_heap_text">The
+        <xliff:g id="proc" example="com.android.example">%1$s</xliff:g> process has exceeded
+        its memory limit of <xliff:g id="size" example="350MB">%2$s</xliff:g>. A heap dump is available
         for you to share with its developer.  Be careful: this heap dump can contain any
         of your personal information that the application has access to.</string>
 
+    <!-- Text of dialog prompting the user to share a heap dump for a system process [CHAR LIMIT=NONE] -->
+    <string name="dump_heap_system_text">The
+        <xliff:g id="proc" example="Android System">%1$s</xliff:g> process has exceeded
+        its memory limit of <xliff:g id="size" example="350MB">%2$s</xliff:g>. A heap dump is available
+        for you to share. Be careful: this heap dump can contain any sensitive personal information
+        that the process has access to.</string>
+
+    <!-- Text of dialog prompting the user to share a heap dump that they initiated [CHAR LIMIT=NONE] -->
+    <string name="dump_heap_ready_text">A heap dump of
+        <xliff:g id="proc" example="com.android.example">%1$s</xliff:g>\u2019s process is available
+        for you to share. Be careful: this heap dump may contain any sensitive personal information
+        that the process has access to.</string>
+
     <!-- Displayed in the title of the chooser for things to do with text that
          is to be sent to another application. For example, I can send
          text through SMS or IM.  A dialog with those choices would be shown,
@@ -5302,6 +5320,21 @@
     <string name="battery_saver_sticky_disabled_notification_title">Battery Saver won\u2019t reactivate until battery low again</string>
     <!-- Summary of notification letting users know why battery saver didn't turn back on automatically after the device was unplugged [CHAR_LIMIT=NONE] -->
     <string name="battery_saver_sticky_disabled_notification_summary">Battery has been charged to a sufficient level. Battery Saver won\u2019t reactivate until the battery is low again.</string>
+    <!-- Title of notification letting users know the battery level at the time the notification was posted [CHAR_LIMIT=80] -->
+    <string name="battery_saver_charged_notification_title" product="default">Phone <xliff:g id="charge level" example="90%">%1$s</xliff:g> charged</string>
+    <!-- Title of notification letting users know the battery level at the time the notification was posted [CHAR_LIMIT=80] -->
+    <string name="battery_saver_charged_notification_title" product="tablet">Tablet <xliff:g id="charge level" example="90%">%1$s</xliff:g> charged</string>
+    <!-- Title of notification letting users know the battery level at the time the notification was posted [CHAR_LIMIT=80] -->
+    <string name="battery_saver_charged_notification_title" product="device">Device <xliff:g id="charge level" example="90%">%1$s</xliff:g> charged</string>
+    <!-- Summary of notification letting users know that battery saver is now off [CHAR_LIMIT=NONE] -->
+    <string name="battery_saver_off_notification_summary">Battery Saver is off. Features no longer restricted.</string>
+    <!-- Alternative summary of notification letting users know that battery saver has been turned off.
+     If it's easy to translate the difference between "Battery Saver turned off. Features no longer restricted."
+     and "Battery Saver is off. Features no longer restricted." into the target language,
+     then translate "Battery Saver turned off. Features no longer restricted."
+     If the translation doesn't make a difference or the difference is hard to capture in the target language,
+     then translate "Battery Saver is off. Features no longer restricted." instead. [CHAR_LIMIT=NONE] -->
+    <string name="battery_saver_off_alternative_notification_summary">Battery Saver turned off. Features no longer restricted.</string>
 
     <!-- Description of media type: folder or directory that contains additional files. [CHAR LIMIT=32] -->
     <string name="mime_type_folder">Folder</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ba964bb..012f736 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1713,6 +1713,7 @@
   <java-symbol type="bool" name="config_enableLockScreenRotation" />
   <java-symbol type="bool" name="config_enableLockScreenTranslucentDecor" />
   <java-symbol type="bool" name="config_enableTranslucentDecor" />
+  <java-symbol type="bool" name="config_forceShowSystemBars" />
   <java-symbol type="bool" name="config_lidControlsScreenLock" />
   <java-symbol type="bool" name="config_lidControlsSleep" />
   <java-symbol type="bool" name="config_lockDayNightMode" />
@@ -2114,8 +2115,11 @@
   <java-symbol type="string" name="device_storage_monitor_notification_channel" />
   <java-symbol type="string" name="dlg_ok" />
   <java-symbol type="string" name="dump_heap_notification" />
+  <java-symbol type="string" name="dump_heap_ready_notification" />
   <java-symbol type="string" name="dump_heap_notification_detail" />
   <java-symbol type="string" name="dump_heap_text" />
+  <java-symbol type="string" name="dump_heap_ready_text" />
+  <java-symbol type="string" name="dump_heap_system_text" />
   <java-symbol type="string" name="dump_heap_title" />
   <java-symbol type="string" name="factorytest_failed" />
   <java-symbol type="string" name="factorytest_no_action" />
@@ -2761,6 +2765,7 @@
   <java-symbol type="string" name="chooser_no_direct_share_targets" />
   <java-symbol type="drawable" name="chooser_row_layer_list" />
   <java-symbol type="dimen" name="chooser_view_spacing" />
+  <java-symbol type="dimen" name="chooser_target_width" />
   <java-symbol type="dimen" name="chooser_edge_margin_thin" />
   <java-symbol type="dimen" name="chooser_edge_margin_normal" />
   <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
@@ -2778,7 +2783,6 @@
 
   <java-symbol type="layout" name="chooser_row" />
   <java-symbol type="layout" name="chooser_row_direct_share" />
-  <java-symbol type="id" name="target_badge" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
   <java-symbol type="string" name="config_radio_access_family" />
@@ -2831,6 +2835,7 @@
   <java-symbol type="string" name="config_packagedKeyboardName" />
   <java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
   <java-symbol type="integer" name="config_navBarOpacityMode" />
+  <java-symbol type="integer" name="config_navBarInteractionMode" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
   <!-- EditText suggestion popup. -->
@@ -3648,6 +3653,9 @@
   <java-symbol type="string" name="battery_saver_notification_channel_name" />
   <java-symbol type="string" name="battery_saver_sticky_disabled_notification_title" />
   <java-symbol type="string" name="battery_saver_sticky_disabled_notification_summary" />
+  <java-symbol type="string" name="battery_saver_charged_notification_title" />
+  <java-symbol type="string" name="battery_saver_off_notification_summary" />
+  <java-symbol type="string" name="battery_saver_off_alternative_notification_summary" />
   <java-symbol type="string" name="dynamic_mode_notification_channel_name" />
   <java-symbol type="string" name="dynamic_mode_notification_title" />
   <java-symbol type="string" name="dynamic_mode_notification_summary" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 85947bd..8fc6a96 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -129,7 +129,7 @@
                     Settings.Global.AUTOFILL_LOGGING_LEVEL,
                     Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
-                    Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
+                    Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
index 72d1ab1..e1ccd75 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
@@ -64,7 +64,9 @@
                         null,
                         null,
                         null,
-                        null);
+                        null,
+                        0,
+                        0);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
@@ -98,7 +100,9 @@
                         null,
                         null,
                         null,
-                        null);
+                        null,
+                        0,
+                        0);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
index ccf8607..2e97e63 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
@@ -82,7 +82,9 @@
                         null,
                         null,
                         null,
-                        createRemoteActionTemplates());
+                        createRemoteActionTemplates(),
+                        0,
+                        0);
 
         List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -121,7 +123,9 @@
                         null,
                         null,
                         null,
-                        createRemoteActionTemplates());
+                        createRemoteActionTemplates(),
+                        0,
+                        0);
 
         List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -156,7 +160,9 @@
                         null,
                         null,
                         null,
-                        null);
+                        null,
+                        0,
+                        0);
 
         mTemplateClassificationIntentFactory.create(
                 InstrumentationRegistry.getContext(),
@@ -189,7 +195,9 @@
                         null,
                         null,
                         null,
-                        new RemoteActionTemplate[0]);
+                        new RemoteActionTemplate[0],
+                        0,
+                        0);
 
         mTemplateClassificationIntentFactory.create(
                 InstrumentationRegistry.getContext(),
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 185fa07..8c2375e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -599,7 +599,7 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -629,7 +629,7 @@
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 5e119e2..afb5071 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -112,7 +112,6 @@
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
-        <permission name="android.permission.CLEAR_APP_USER_DATA"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
     </privapp-permissions>
 
@@ -309,6 +308,8 @@
         <permission name="android.permission.STATUS_BAR_SERVICE"/>
         <permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"/>
         <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
+        <permission name="android.permission.SET_WALLPAPER" />
+        <permission name="android.permission.SET_WALLPAPER_COMPONENT" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
@@ -331,9 +332,9 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.dynandroid">
+    <privapp-permissions package="com.android.dynsystem">
         <permission name="android.permission.REBOOT"/>
-        <permission name="android.permission.MANAGE_DYNAMIC_ANDROID"/>
+        <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
     </privapp-permissions>
 
 </permissions>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 346c7ab..c485461 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -229,7 +229,8 @@
     public static final int VERTICAL_TEXT_FLAG = 0x1000;
 
     // These flags are always set on a new/reset paint, even if flags 0 is passed.
-    static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;
+    static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG
+            | FILTER_BITMAP_FLAG;
 
     /**
      * Font hinter option that disables font hinting.
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 9db7533..b6d8fa1 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -42,7 +42,7 @@
  * String text = "Hello, Android.";
  * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
  *      .appendStyleRun(paint, 7, false)  // Use paint for "Hello, "
- *      .appendStyleRun(bigPaint, 8, false)  // Use bigPaint for "Hello, "
+ *      .appendStyleRun(bigPaint, 8, false)  // Use bigPaint for "Android."
  *      .build();
  * </code>
  * </pre>
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 9916da5..b8ebf3b 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -439,34 +439,47 @@
     LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
 
     if (bufferInfo->dequeue_fence != -1) {
-        int fence_clone = dup(bufferInfo->dequeue_fence);
-        if (fence_clone == -1) {
-            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno);
-            sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
-        } else {
-            VkSemaphoreCreateInfo semaphoreInfo;
-            semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-            semaphoreInfo.pNext = nullptr;
-            semaphoreInfo.flags = 0;
-            VkSemaphore semaphore;
-            VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
-            LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
-                                err);
+        struct sync_file_info* finfo = sync_file_info(bufferInfo->dequeue_fence);
+        bool isSignalPending = false;
+        if (finfo != NULL) {
+            isSignalPending = finfo->status != 1;
+            sync_file_info_free(finfo);
+        }
+        if (isSignalPending) {
+            int fence_clone = dup(bufferInfo->dequeue_fence);
+            if (fence_clone == -1) {
+                ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno),
+                      errno);
+                sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+            } else {
+                VkSemaphoreCreateInfo semaphoreInfo;
+                semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+                semaphoreInfo.pNext = nullptr;
+                semaphoreInfo.flags = 0;
+                VkSemaphore semaphore;
+                VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+                LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
+                                    err);
 
-            VkImportSemaphoreFdInfoKHR importInfo;
-            importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
-            importInfo.pNext = nullptr;
-            importInfo.semaphore = semaphore;
-            importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
-            importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
-            importInfo.fd = fence_clone;
+                VkImportSemaphoreFdInfoKHR importInfo;
+                importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+                importInfo.pNext = nullptr;
+                importInfo.semaphore = semaphore;
+                importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+                importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+                importInfo.fd = fence_clone;
 
-            err = mImportSemaphoreFdKHR(mDevice, &importInfo);
-            LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
+                err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+                LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
 
-            GrBackendSemaphore backendSemaphore;
-            backendSemaphore.initVulkan(semaphore);
-            bufferInfo->skSurface->wait(1, &backendSemaphore);
+                GrBackendSemaphore backendSemaphore;
+                backendSemaphore.initVulkan(semaphore);
+                bufferInfo->skSurface->wait(1, &backendSemaphore);
+                // The following flush blocks the GPU immediately instead of waiting for other
+                // drawing ops. It seems dequeue_fence is not respected otherwise.
+                //TODO: remove the flush after finding why backendSemaphore is not working.
+                bufferInfo->skSurface->flush();
+            }
         }
     }
 
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index c03c3a8..a98eb32 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -256,11 +256,44 @@
         vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
     }
 
-    uint64_t producerUsage =
-            AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
-    uint64_t consumerUsage;
-    native_window_get_consumer_usage(window, &consumerUsage);
-    windowInfo.windowUsageFlags = consumerUsage | producerUsage;
+    if (nullptr != vkManager.mGetPhysicalDeviceImageFormatProperties2) {
+        VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
+        externalImageFormatInfo.sType =
+                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+        externalImageFormatInfo.pNext = nullptr;
+        externalImageFormatInfo.handleType =
+                VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+
+        VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
+        imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+        imageFormatInfo.pNext = &externalImageFormatInfo;
+        imageFormatInfo.format = vkPixelFormat;
+        imageFormatInfo.type = VK_IMAGE_TYPE_2D;
+        imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+        imageFormatInfo.usage = usageFlags;
+        imageFormatInfo.flags = 0;
+
+        VkAndroidHardwareBufferUsageANDROID hwbUsage;
+        hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+        hwbUsage.pNext = nullptr;
+
+        VkImageFormatProperties2 imgFormProps;
+        imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+        imgFormProps.pNext = &hwbUsage;
+
+        res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice,
+                                                                 &imageFormatInfo, &imgFormProps);
+        if (VK_SUCCESS != res) {
+            ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
+            return nullptr;
+        }
+
+        windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
+
+    } else {
+        ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
+        return nullptr;
+    }
 
     /*
      * Now we attempt to modify the window!
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 8507c83..5384061 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -36,6 +38,8 @@
     private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
     private static final int HAS_DRIFT = (1<<5);
     private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
+    private static final int HAS_ELAPSED_REALTIME_NANOS = (1 << 7);
+    private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS = (1 << 8);
 
     // End enumerations in sync with gps.h
 
@@ -49,6 +53,8 @@
     private double mDriftNanosPerSecond;
     private double mDriftUncertaintyNanosPerSecond;
     private int mHardwareClockDiscontinuityCount;
+    private long mElapsedRealtimeNanos;
+    private long mElapsedRealtimeUncertaintyNanos;
 
     /**
      * @hide
@@ -74,6 +80,8 @@
         mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
         mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
         mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
+        mElapsedRealtimeNanos = clock.mElapsedRealtimeNanos;
+        mElapsedRealtimeUncertaintyNanos = clock.mElapsedRealtimeUncertaintyNanos;
     }
 
     /**
@@ -167,6 +175,7 @@
      * <p>This value is often effectively zero (it is the reference clock by which all other times
      * and time uncertainties are measured), and thus this field may often be 0, or not provided.
      */
+    @FloatRange(from = 0.0f)
     public double getTimeUncertaintyNanos() {
         return mTimeUncertaintyNanos;
     }
@@ -176,7 +185,7 @@
      * @hide
      */
     @TestApi
-    public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
+    public void setTimeUncertaintyNanos(@FloatRange(from = 0.0f) double timeUncertaintyNanos) {
         setFlag(HAS_TIME_UNCERTAINTY);
         mTimeUncertaintyNanos = timeUncertaintyNanos;
     }
@@ -297,6 +306,7 @@
      *
      * <p>The value is only available if {@link #hasBiasUncertaintyNanos()} is {@code true}.
      */
+    @FloatRange(from = 0.0f)
     public double getBiasUncertaintyNanos() {
         return mBiasUncertaintyNanos;
     }
@@ -306,7 +316,7 @@
      * @hide
      */
     @TestApi
-    public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
+    public void setBiasUncertaintyNanos(@FloatRange(from = 0.0f) double biasUncertaintyNanos) {
         setFlag(HAS_BIAS_UNCERTAINTY);
         mBiasUncertaintyNanos = biasUncertaintyNanos;
     }
@@ -379,6 +389,7 @@
      * <p>The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is
      * {@code true}.
      */
+    @FloatRange(from = 0.0f)
     public double getDriftUncertaintyNanosPerSecond() {
         return mDriftUncertaintyNanosPerSecond;
     }
@@ -388,7 +399,8 @@
      * @hide
      */
     @TestApi
-    public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
+    public void setDriftUncertaintyNanosPerSecond(
+            @FloatRange(from = 0.0f) double driftUncertaintyNanosPerSecond) {
         setFlag(HAS_DRIFT_UNCERTAINTY);
         mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
     }
@@ -404,6 +416,90 @@
     }
 
     /**
+     * Returns {@code true} if {@link #getElapsedRealtimeNanos()} is available, {@code false}
+     * otherwise.
+     */
+    public boolean hasElapsedRealtimeNanos() {
+        return isFlagSet(HAS_ELAPSED_REALTIME_NANOS);
+    }
+
+    /**
+     * Returns the elapsed real-time of this clock since system boot, in nanoseconds.
+     *
+     * <p>The value is only available if {@link #hasElapsedRealtimeNanos()} is
+     * {@code true}.
+     */
+    public long getElapsedRealtimeNanos() {
+        return mElapsedRealtimeNanos;
+    }
+
+    /**
+     * Sets the elapsed real-time of this clock since system boot, in nanoseconds.
+     * @hide
+     */
+    @TestApi
+    public void setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
+        setFlag(HAS_ELAPSED_REALTIME_NANOS);
+        mElapsedRealtimeNanos = elapsedRealtimeNanos;
+    }
+
+    /**
+     * Resets the elapsed real-time of this clock since system boot, in nanoseconds.
+     * @hide
+     */
+    @TestApi
+    public void resetElapsedRealtimeNanos() {
+        resetFlag(HAS_ELAPSED_REALTIME_NANOS);
+        mElapsedRealtimeNanos = 0;
+    }
+
+    /**
+     * Returns {@code true} if {@link #getElapsedRealtimeUncertaintyNanos()} is available, {@code
+     * false} otherwise.
+     */
+    public boolean hasElapsedRealtimeUncertaintyNanos() {
+        return isFlagSet(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
+    }
+
+    /**
+     * Gets the estimate of the relative precision of the alignment of the
+     * {@link #getElapsedRealtimeNanos()} timestamp, with the reported measurements in
+     * nanoseconds (68% confidence).
+     *
+     * <p>The value is only available if {@link #hasElapsedRealtimeUncertaintyNanos()} is
+     * {@code true}.
+     */
+    @IntRange(from = 0)
+    public long getElapsedRealtimeUncertaintyNanos() {
+        return mElapsedRealtimeUncertaintyNanos;
+    }
+
+    /**
+     * Sets the estimate of the relative precision of the alignment of the
+     * {@link #getElapsedRealtimeNanos()} timestamp, with the reported measurements in
+     * nanoseconds (68% confidence).
+     * @hide
+     */
+    @TestApi
+    public void setElapsedRealtimeUncertaintyNanos(
+            @IntRange(from = 0) long elapsedRealtimeUncertaintyNanos) {
+        setFlag(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
+        mElapsedRealtimeUncertaintyNanos = elapsedRealtimeUncertaintyNanos;
+    }
+
+    /**
+     * Resets the estimate of the relative precision of the alignment of the
+     * {@link #getElapsedRealtimeNanos()} timestamp, with the reported measurements in
+     * nanoseconds (68% confidence).
+     * @hide
+     */
+    @TestApi
+    public void resetElapsedRealtimeUncertaintyNanos() {
+        resetFlag(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
+        mElapsedRealtimeUncertaintyNanos = Long.MAX_VALUE;
+    }
+
+    /**
      * Gets count of hardware clock discontinuities.
      *
      * <p>When this value stays the same, vs. a value in a previously reported {@link GnssClock}, it
@@ -446,6 +542,8 @@
             gpsClock.mDriftNanosPerSecond = parcel.readDouble();
             gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
             gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
+            gpsClock.mElapsedRealtimeNanos = parcel.readLong();
+            gpsClock.mElapsedRealtimeUncertaintyNanos = parcel.readLong();
 
             return gpsClock;
         }
@@ -468,6 +566,8 @@
         parcel.writeDouble(mDriftNanosPerSecond);
         parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
         parcel.writeInt(mHardwareClockDiscontinuityCount);
+        parcel.writeLong(mElapsedRealtimeNanos);
+        parcel.writeLong(mElapsedRealtimeUncertaintyNanos);
     }
 
     @Override
@@ -514,6 +614,16 @@
                 "HardwareClockDiscontinuityCount",
                 mHardwareClockDiscontinuityCount));
 
+        builder.append(String.format(
+                format,
+                "ElapsedRealtimeNanos",
+                hasElapsedRealtimeNanos() ? mElapsedRealtimeNanos : null));
+
+        builder.append(String.format(
+                format,
+                "ElapsedRealtimeUncertaintyNanos",
+                hasElapsedRealtimeUncertaintyNanos() ? mElapsedRealtimeUncertaintyNanos : null));
+
         return builder.toString();
     }
 
@@ -528,6 +638,8 @@
         resetDriftNanosPerSecond();
         resetDriftUncertaintyNanosPerSecond();
         setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
+        resetElapsedRealtimeNanos();
+        resetElapsedRealtimeUncertaintyNanos();
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index e5fd0d3..b4be219 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -238,6 +238,8 @@
      *    window after the end of that call.
      * 3. If the device is in a emergency callback state, this is provided by querying
      *    TelephonyManager.
+     * 4. If the user has recently sent an Emergency SMS and telephony reports that it is in
+     *    emergency SMS mode, this is provided by querying TelephonyManager.
      * @return true if is considered in user initiated emergency mode for NI purposes
      */
     public boolean getInEmergency() {
@@ -246,7 +248,9 @@
                 && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis)
                         < mEmergencyExtensionMillis);
         boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
-        return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension;
+        boolean isInEmergencySmsMode = mTelephonyManager.isInEmergencySmsMode();
+        return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension
+                || isInEmergencySmsMode;
     }
 
     public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
diff --git a/media/Android.bp b/media/Android.bp
index 86dc509..3480181 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -90,7 +90,6 @@
         "apex/java/android/media/DataSourceDesc.java",
         "apex/java/android/media/UriDataSourceDesc.java",
         "apex/java/android/media/FileDataSourceDesc.java",
-        "apex/java/android/media/CallbackDataSourceDesc.java",
         "apex/java/android/media/Media2Utils.java",
         "apex/java/android/media/MediaPlayer2Utils.java",
         "apex/java/android/media/MediaPlayer2.java",
@@ -98,6 +97,7 @@
         "apex/java/android/media/Media2HTTPConnection.java",
         "apex/java/android/media/RoutingDelegate.java",
         "apex/java/android/media/BufferingParams.java",
+        "apex/java/android/media/ProxyDataSourceCallback.java",
     ],
 }
 
diff --git a/media/apex/java/android/media/CallbackDataSourceDesc.java b/media/apex/java/android/media/CallbackDataSourceDesc.java
deleted file mode 100644
index d9db62e..0000000
--- a/media/apex/java/android/media/CallbackDataSourceDesc.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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.media;
-
-import android.annotation.NonNull;
-import android.annotation.TestApi;
-
-/**
- * Structure of data source descriptor for sources using callback.
- *
- * Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and
- * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
- *
- * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
- * @hide
- */
-@TestApi
-public class CallbackDataSourceDesc extends DataSourceDesc {
-    private DataSourceCallback mDataSourceCallback;
-
-    CallbackDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
-            DataSourceCallback dataSourceCallback) {
-        super(mediaId, startPositionMs, endPositionMs);
-        mDataSourceCallback = dataSourceCallback;
-    }
-
-    /**
-     * Return the DataSourceCallback of this data source.
-     * @return the DataSourceCallback of this data source
-     */
-    public @NonNull DataSourceCallback getDataSourceCallback() {
-        return mDataSourceCallback;
-    }
-}
diff --git a/media/apex/java/android/media/DataSourceCallback.java b/media/apex/java/android/media/DataSourceCallback.java
index 6515bd6..c297ecd 100644
--- a/media/apex/java/android/media/DataSourceCallback.java
+++ b/media/apex/java/android/media/DataSourceCallback.java
@@ -32,8 +32,12 @@
  * you don't need to do your own synchronization unless you're modifying the
  * DataSourceCallback from another thread while it's being used by the framework.</p>
  *
+ * @hide
  */
 public abstract class DataSourceCallback implements Closeable {
+
+    public static final int END_OF_STREAM = -1;
+
     /**
      * Called to request data from the given position.
      *
@@ -49,7 +53,7 @@
      * @param offset the offset within buffer to read the data into.
      * @param size the number of bytes to read.
      * @throws IOException on fatal errors.
-     * @return the number of bytes read, or -1 if end of stream is reached.
+     * @return the number of bytes read, or {@link #END_OF_STREAM} if end of stream is reached.
      */
     public abstract int readAt(long position, @NonNull byte[] buffer, int offset, int size)
             throws IOException;
diff --git a/media/apex/java/android/media/DataSourceDesc.java b/media/apex/java/android/media/DataSourceDesc.java
index be80c22..d00ff2a 100644
--- a/media/apex/java/android/media/DataSourceDesc.java
+++ b/media/apex/java/android/media/DataSourceDesc.java
@@ -125,7 +125,6 @@
         private static final int SOURCE_TYPE_UNKNOWN = 0;
         private static final int SOURCE_TYPE_URI = 1;
         private static final int SOURCE_TYPE_FILE = 2;
-        private static final int SOURCE_TYPE_CALLBACK = 3;
 
         private int mSourceType = SOURCE_TYPE_UNKNOWN;
         private String mMediaId;
@@ -142,9 +141,6 @@
         private long mOffset = 0;
         private long mLength = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
 
-        // For CallbackDataSourceDesc
-        private DataSourceCallback mDataSourceCallback;
-
         /**
          * Constructs a new BuilderBase with the defaults.
          */
@@ -173,9 +169,6 @@
                 mUri = ((UriDataSourceDesc) dsd).getUri();
                 mHeader = ((UriDataSourceDesc) dsd).getHeaders();
                 mCookies = ((UriDataSourceDesc) dsd).getCookies();
-            } else if (dsd instanceof CallbackDataSourceDesc) {
-                mSourceType = SOURCE_TYPE_CALLBACK;
-                mDataSourceCallback = ((CallbackDataSourceDesc) dsd).getDataSourceCallback();
             } else {
                 throw new IllegalStateException("Unknown source type:" + mSourceType);
             }
@@ -204,9 +197,6 @@
             } else if (mSourceType == SOURCE_TYPE_URI) {
                 desc = new UriDataSourceDesc(
                         mMediaId, mStartPositionMs, mEndPositionMs, mUri, mHeader, mCookies);
-            } else if (mSourceType == SOURCE_TYPE_CALLBACK) {
-                desc = new CallbackDataSourceDesc(
-                        mMediaId, mStartPositionMs, mEndPositionMs, mDataSourceCallback);
             } else {
                 throw new IllegalStateException("Unknown source type:" + mSourceType);
             }
@@ -326,7 +316,7 @@
 
         /**
          * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
-         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
+         * seekable (N.B. a LocalSocket is not seekable). When the {@link DataSourceDesc}
          * created by this builder is passed to {@link MediaPlayer2} via
          * {@link MediaPlayer2#setDataSource},
          * {@link MediaPlayer2#setNextDataSource} or
@@ -347,7 +337,7 @@
 
         /**
          * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
-         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
+         * seekable (N.B. a LocalSocket is not seekable). When the {@link DataSourceDesc}
          * created by this builder is passed to {@link MediaPlayer2} via
          * {@link MediaPlayer2#setDataSource},
          * {@link MediaPlayer2#setNextDataSource} or
@@ -367,7 +357,9 @@
         public Builder setDataSource(
                 @NonNull ParcelFileDescriptor pfd, long offset, long length) {
             setSourceType(SOURCE_TYPE_FILE);
-            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
+            if (pfd == null) {
+                throw new NullPointerException("pfd cannot be null.");
+            }
             if (offset < 0) {
                 offset = 0;
             }
@@ -380,20 +372,6 @@
             return this;
         }
 
-        /**
-         * Sets the data source (DataSourceCallback) to use.
-         *
-         * @param dscb the DataSourceCallback for the media to play
-         * @return the same Builder instance.
-         * @throws NullPointerException if dscb is null.
-         */
-        public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) {
-            setSourceType(SOURCE_TYPE_CALLBACK);
-            Media2Utils.checkArgument(dscb != null, "data source cannot be null.");
-            mDataSourceCallback = dscb;
-            return this;
-        }
-
         private void setSourceType(int type) {
             if (mSourceType != SOURCE_TYPE_UNKNOWN) {
                 throw new IllegalStateException("Source is already set. type=" + mSourceType);
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 68a46ed..19bb258 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -878,22 +878,27 @@
             throws IOException {
         Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
 
-        if (dsd instanceof CallbackDataSourceDesc) {
-            CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd;
-            handleDataSource(isCurrent,
-                             srcId,
-                             cbDSD.getDataSourceCallback(),
-                             cbDSD.getStartPosition(),
-                             cbDSD.getEndPosition());
-        } else if (dsd instanceof FileDataSourceDesc) {
+        if (dsd instanceof FileDataSourceDesc) {
             FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
-            handleDataSource(isCurrent,
-                             srcId,
-                             fileDSD.getParcelFileDescriptor(),
-                             fileDSD.getOffset(),
-                             fileDSD.getLength(),
-                             fileDSD.getStartPosition(),
-                             fileDSD.getEndPosition());
+            ParcelFileDescriptor pfd = fileDSD.getParcelFileDescriptor();
+            if (pfd.getStatSize() == -1) {
+                // Underlying pipeline doesn't understand '-1' size. Create a wrapper for
+                // translation.
+                // TODO: Make native code handle '-1' size.
+                handleDataSource(isCurrent,
+                        srcId,
+                        new ProxyDataSourceCallback(pfd),
+                        fileDSD.getStartPosition(),
+                        fileDSD.getEndPosition());
+            } else {
+                handleDataSource(isCurrent,
+                        srcId,
+                        pfd,
+                        fileDSD.getOffset(),
+                        fileDSD.getLength(),
+                        fileDSD.getStartPosition(),
+                        fileDSD.getEndPosition());
+            }
         } else if (dsd instanceof UriDataSourceDesc) {
             UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
             handleDataSource(isCurrent,
@@ -1963,6 +1968,17 @@
     private native byte[] native_invoke(byte[] request);
 
     /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIA_TRACK_TYPE", value = {
+            TrackInfo.MEDIA_TRACK_TYPE_VIDEO,
+            TrackInfo.MEDIA_TRACK_TYPE_AUDIO,
+            TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TrackType {}
+
+    /**
      * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
      *
      * @see MediaPlayer2#getTrackInfo
@@ -2009,10 +2025,11 @@
         public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
         public static final int MEDIA_TRACK_TYPE_METADATA = 5;
 
+        final int mId;
         final int mTrackType;
         final MediaFormat mFormat;
 
-        static TrackInfo create(Iterator<Value> in) {
+        static TrackInfo create(int idx, Iterator<Value> in) {
             int trackType = in.next().getInt32Value();
             // TODO: build the full MediaFormat; currently we are using createSubtitleFormat
             // even for audio/video tracks, meaning we only set the mime and language.
@@ -2025,11 +2042,12 @@
                 format.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
                 format.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
             }
-            return new TrackInfo(trackType, format);
+            return new TrackInfo(idx, trackType, format);
         }
 
         /** @hide */
-        TrackInfo(int type, MediaFormat format) {
+        TrackInfo(int id, int type, MediaFormat format) {
+            mId = id;
             mTrackType = type;
             mFormat = format;
         }
@@ -2116,7 +2134,7 @@
         }
         TrackInfo[] trackInfo = new TrackInfo[size];
         for (int i = 0; i < size; ++i) {
-            trackInfo[i] = TrackInfo.create(in);
+            trackInfo[i] = TrackInfo.create(i, in);
         }
         return trackInfo;
     }
@@ -2124,54 +2142,56 @@
     /**
      * Returns the index of the audio, video, or subtitle track currently selected for playback.
      * The return value is an index into the array returned by {@link #getTrackInfo}, and can
-     * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}.
+     * be used in calls to {@link #selectTrack(TrackInfo)} or {@link #deselectTrack(TrackInfo)}.
      * Same as {@link #getSelectedTrack(DataSourceDesc, int)} with
      * {@code dsd = getCurrentDataSource()}.
      *
      * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
      * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
      * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
-     * @return index of the audio, video, or subtitle track currently selected for playback;
-     * a negative integer is returned when there is no selected track for {@code trackType} or
+     * @return metadata corresponding to the audio, video, or subtitle track currently selected for
+     * playback; {@code null} is returned when there is no selected track for {@code trackType} or
      * when {@code trackType} is not one of audio, video, or subtitle.
      * @throws IllegalStateException if called after {@link #close()}
      * @throws NullPointerException if current data source is null
      *
      * @see #getTrackInfo()
-     * @see #selectTrack(int)
-     * @see #deselectTrack(int)
+     * @see #selectTrack(TrackInfo)
+     * @see #deselectTrack(TrackInfo)
      */
-    public int getSelectedTrack(int trackType) {
+    @Nullable
+    public TrackInfo getSelectedTrack(@TrackType int trackType) {
         return getSelectedTrack(getCurrentDataSource(), trackType);
     }
 
     /**
      * Returns the index of the audio, video, or subtitle track currently selected for playback.
      * The return value is an index into the array returned by {@link #getTrackInfo}, and can
-     * be used in calls to {@link #selectTrack(DataSourceDesc, int)} or
-     * {@link #deselectTrack(DataSourceDesc, int)}.
+     * be used in calls to {@link #selectTrack(DataSourceDesc, TrackInfo)} or
+     * {@link #deselectTrack(DataSourceDesc, TrackInfo)}.
      *
      * @param dsd the descriptor of data source of which you want to get selected track
      * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
      * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
      * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
-     * @return index of the audio, video, or subtitle track currently selected for playback;
-     * a negative integer is returned when there is no selected track for {@code trackType} or
+     * @return metadata corresponding to the audio, video, or subtitle track currently selected for
+     * playback; {@code null} is returned when there is no selected track for {@code trackType} or
      * when {@code trackType} is not one of audio, video, or subtitle.
      * @throws IllegalStateException if called after {@link #close()}
      * @throws NullPointerException if dsd is null
      *
      * @see #getTrackInfo(DataSourceDesc)
-     * @see #selectTrack(DataSourceDesc, int)
-     * @see #deselectTrack(DataSourceDesc, int)
+     * @see #selectTrack(DataSourceDesc, TrackInfo)
+     * @see #deselectTrack(DataSourceDesc, TrackInfo)
      */
-    public int getSelectedTrack(@NonNull DataSourceDesc dsd, int trackType) {
+    @Nullable
+    public TrackInfo getSelectedTrack(@NonNull DataSourceDesc dsd, @TrackType int trackType) {
         if (dsd == null) {
             throw new NullPointerException("non-null dsd is expected");
         }
         SourceInfo sourceInfo = getSourceInfo(dsd);
         if (sourceInfo == null) {
-            return -1;
+            return null;
         }
 
         PlayerMessage request = PlayerMessage.newBuilder()
@@ -2181,26 +2201,30 @@
                 .build();
         PlayerMessage response = invoke(request);
         if (response == null) {
-            return -1;
+            return null;
         }
-        return response.getValues(0).getInt32Value();
+        // TODO: return full TrackInfo data from native player instead of index
+        final int idx = response.getValues(0).getInt32Value();
+        final List<TrackInfo> trackInfos = getTrackInfo(dsd);
+        return trackInfos.isEmpty() ? null : trackInfos.get(idx);
     }
 
     /**
      * Selects a track of current data source.
-     * Same as {@link #selectTrack(DataSourceDesc, int)} with
+     * Same as {@link #selectTrack(DataSourceDesc, TrackInfo)} with
      * {@code dsd = getCurrentDataSource()}.
      *
-     * @param index the index of the track to be selected. The valid range of the index
-     * is 0..total number of track - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo()} method.
+     * @param trackInfo metadata corresponding to the track to be selected. A {@code trackInfo}
+     * object can be obtained from {@link #getTrackInfo()}.
      * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
      *
+     * This is an asynchronous call.
+     *
      * @see MediaPlayer2#getTrackInfo()
      */
-    // This is an asynchronous call.
-    public @NonNull Object selectTrack(int index) {
-        return selectTrack(getCurrentDataSource(), index);
+    @NonNull
+    public Object selectTrack(@NonNull TrackInfo trackInfo) {
+        return selectTrack(getCurrentDataSource(), trackInfo);
     }
 
     /**
@@ -2225,38 +2249,40 @@
      * in that an audio track can only be selected in the <em>Prepared</em> state.
      * </p>
      * @param dsd the descriptor of data source of which you want to select track
-     * @param index the index of the track to be selected. The valid range of the index
-     * is 0..total number of track - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo(DataSourceDesc)} method.
+     * @param trackInfo metadata corresponding to the track to be selected. A {@code trackInfo}
+     * object can be obtained from {@link #getTrackInfo()}.
      * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
      *
+     * This is an asynchronous call.
+     *
      * @see MediaPlayer2#getTrackInfo(DataSourceDesc)
      */
-    // This is an asynchronous call.
-    public @NonNull Object selectTrack(@NonNull DataSourceDesc dsd, int index) {
+    @NonNull
+    public Object selectTrack(@NonNull DataSourceDesc dsd, @NonNull TrackInfo trackInfo) {
         return addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) {
             @Override
             void process() {
-                selectOrDeselectTrack(dsd, index, true /* select */);
+                selectOrDeselectTrack(dsd, trackInfo.mId, true /* select */);
             }
         });
     }
 
     /**
      * Deselect a track of current data source.
-     * Same as {@link #deselectTrack(DataSourceDesc, int)} with
+     * Same as {@link #deselectTrack(DataSourceDesc, TrackInfo)} with
      * {@code dsd = getCurrentDataSource()}.
      *
-     * @param index the index of the track to be deselected. The valid range of the index
-     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo()} method.
+     * @param trackInfo metadata corresponding to the track to be selected. A {@code trackInfo}
+     * object can be obtained from {@link #getTrackInfo()}.
      * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
      *
+     * This is an asynchronous call.
+     *
      * @see MediaPlayer2#getTrackInfo()
      */
-    // This is an asynchronous call.
-    public @NonNull Object deselectTrack(int index) {
-        return deselectTrack(getCurrentDataSource(), index);
+    @NonNull
+    public Object deselectTrack(@NonNull TrackInfo trackInfo) {
+        return deselectTrack(getCurrentDataSource(), trackInfo);
     }
 
     /**
@@ -2267,19 +2293,20 @@
      * selected before, it throws an exception.
      * </p>
      * @param dsd the descriptor of data source of which you want to deselect track
-     * @param index the index of the track to be deselected. The valid range of the index
-     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo} method.
+     * @param trackInfo metadata corresponding to the track to be selected. A {@code trackInfo}
+     * object can be obtained from {@link #getTrackInfo()}.
      * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
      *
+     * This is an asynchronous call.
+     *
      * @see MediaPlayer2#getTrackInfo(DataSourceDesc)
      */
-    // This is an asynchronous call.
-    public @NonNull Object deselectTrack(@NonNull DataSourceDesc dsd, int index) {
+    @NonNull
+    public Object deselectTrack(@NonNull DataSourceDesc dsd, @NonNull TrackInfo trackInfo) {
         return addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) {
             @Override
             void process() {
-                selectOrDeselectTrack(dsd, index, false /* select */);
+                selectOrDeselectTrack(dsd, trackInfo.mId, false /* select */);
             }
         });
     }
@@ -2640,11 +2667,13 @@
                             return;
                         }
                         Iterator<Value> in = playerMsg.getValuesList().iterator();
-                        SubtitleData data = new SubtitleData(
-                                in.next().getInt32Value(),  // trackIndex
-                                in.next().getInt64Value(),  // startTimeUs
-                                in.next().getInt64Value(),  // durationUs
-                                in.next().getBytesValue().toByteArray());  // data
+                        final int trackIndex = in.next().getInt32Value();
+                        TrackInfo trackInfo = getTrackInfo(dsd).get(trackIndex);
+                        final long startTimeUs = in.next().getInt64Value();
+                        final long durationTimeUs = in.next().getInt64Value();
+                        final byte[] subData = in.next().getBytesValue().toByteArray();
+                        SubtitleData data = new SubtitleData(trackInfo,
+                                startTimeUs, durationTimeUs, subData);
                         sendEvent(new EventNotifier() {
                             @Override
                             public void notify(EventCallback callback) {
@@ -2765,6 +2794,74 @@
     }
 
     /**
+     * Class encapsulating subtitle data, as received through the
+     * {@link EventCallback#onSubtitleData} interface.
+     * <p>
+     * A {@link SubtitleData} object includes:
+     * <ul>
+     * <li> track metadadta in a {@link TrackInfo} object</li>
+     * <li> the start time (in microseconds) of the data</li>
+     * <li> the duration (in microseconds) of the data</li>
+     * <li> the actual data.</li>
+     * </ul>
+     * The data is stored in a byte-array, and is encoded in one of the supported in-band
+     * subtitle formats. The subtitle encoding is determined by the MIME type of the
+     * {@link TrackInfo} of the subtitle track, one of
+     * {@link MediaFormat#MIMETYPE_TEXT_CEA_608}, {@link MediaFormat#MIMETYPE_TEXT_CEA_708},
+     * {@link MediaFormat#MIMETYPE_TEXT_VTT}.
+     */
+    public static final class SubtitleData {
+
+        private TrackInfo mTrackInfo;
+        private long mStartTimeUs;
+        private long mDurationUs;
+        private byte[] mData;
+
+        private SubtitleData(TrackInfo trackInfo, long startTimeUs, long durationUs, byte[] data) {
+            mTrackInfo = trackInfo;
+            mStartTimeUs = startTimeUs;
+            mDurationUs = durationUs;
+            mData = (data != null ? data : new byte[0]);
+        }
+
+        /**
+         * @return metadata of track which contains this subtitle data
+         */
+        @NonNull
+        public TrackInfo getTrackInfo() {
+            return mTrackInfo;
+        }
+
+        /**
+         * @return media time at which the subtitle should start to be displayed in microseconds
+         */
+        public long getStartTimeUs() {
+            return mStartTimeUs;
+        }
+
+        /**
+         * @return the duration in microsecond during which the subtitle should be displayed
+         */
+        public long getDurationUs() {
+            return mDurationUs;
+        }
+
+        /**
+         * Returns the encoded data for the subtitle content.
+         * Encoding format depends on the subtitle type, refer to
+         * <a href="https://en.wikipedia.org/wiki/CEA-708">CEA 708</a>,
+         * <a href="https://en.wikipedia.org/wiki/EIA-608">CEA/EIA 608</a> and
+         * <a href="https://www.w3.org/TR/webvtt1/">WebVTT</a>, defined by the MIME type
+         * of the subtitle track.
+         * @return the encoded subtitle data
+         */
+        @NonNull
+        public byte[] getData() {
+            return mData;
+        }
+    }
+
+    /**
      * Interface definition for callbacks to be invoked when the player has the corresponding
      * events.
      */
@@ -3439,10 +3536,18 @@
 
         /**
          * Mutable builder to create a {@link MediaPlayer2.DrmPreparationInfo} object.
+         *
+         * {@link Builder#Builder(UUID) UUID} must not be null; {@link #setKeyType keyType}
+         * must be one of {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
+         * <p>
+         * When {@link #setKeyType keyType} is {@link MediaDrm#KEY_TYPE_STREAMING},
+         * {@link #setInitData(byte[]) initData} and {@link #setMimeType(String) mimeType}
+         * must not be null; When {@link #setKeyType keyType} is {@link MediaDrm#KEY_TYPE_OFFLINE},
+         * {@link #setKeySetId(byte[]) keySetId} must not be null.
          */
         public static final class Builder {
 
-            private UUID mUUID;
+            private final UUID mUUID;
             private byte[] mKeySetId;
             private byte[] mInitData;
             private String mMimeType;
@@ -3450,15 +3555,11 @@
             private Map<String, String> mOptionalParameters;
 
             /**
-             * Set UUID of the crypto scheme selected to decrypt content. An UUID can be retrieved
-             * from the source listening to {@link MediaPlayer2.DrmEventCallback#onDrmInfo}.
-             *
-             * @param uuid of selected crypto scheme
-             * @return this
+             * @param uuid UUID of the crypto scheme selected to decrypt content. An UUID can be
+             * retrieved from the source listening to {@link DrmEventCallback#onDrmInfo}.
              */
-            public @NonNull Builder setUuid(@NonNull UUID uuid) {
+            public Builder(@NonNull UUID uuid) {
                 this.mUUID = uuid;
-                return this;
             }
 
             /**
@@ -3531,12 +3632,16 @@
             }
 
             /**
-             * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
-             *         settings of this builder
+             * @return an immutable {@link DrmPreparationInfo} based on settings of this builder
              */
-            public @NonNull MediaPlayer2.DrmPreparationInfo build() {
-                return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
-                        mKeyType, mOptionalParameters);
+            @NonNull
+            public DrmPreparationInfo build() {
+                final DrmPreparationInfo info = new DrmPreparationInfo(mUUID, mKeySetId, mInitData,
+                        mMimeType, mKeyType, mOptionalParameters);
+                if (!info.isValid()) {
+                    throw new IllegalArgumentException("invalid DrmPreparationInfo");
+                }
+                return info;
             }
 
         }
@@ -3572,13 +3677,61 @@
             }
             return false;
         }
+
+        /**
+         * @return UUID of the crypto scheme selected to decrypt content.
+         */
+        @NonNull
+        public UUID getUuid() {
+            return mUUID;
+        }
+
+        /**
+         * @return identifier of the persisted offline key.
+         */
+        @Nullable
+        public byte[] getKeySetId() {
+            return mKeySetId;
+        }
+
+        /**
+         * @return container-specific DRM initialization data.
+         */
+        @Nullable
+        public byte[] getInitData() {
+            return mInitData;
+        }
+
+        /**
+         * @return mime type of the content
+         */
+        @Nullable
+        public String getMimeType() {
+            return mMimeType;
+        }
+
+        /**
+         * @return type of the key request.
+         */
+        @MediaPlayer2.MediaDrmKeyType
+        public int getKeyType() {
+            return mKeyType;
+        }
+
+        /**
+         * @return optional parameters to be included in the {@link MediaDrm.KeyRequest}.
+         */
+        @Nullable
+        public Map<String, String> getOptionalParameters() {
+            return mOptionalParameters;
+        }
     }
 
     /**
      * Interface definition for callbacks to be invoked when the player has the corresponding
      * DRM events.
      */
-    public static class DrmEventCallback {
+    public static abstract class DrmEventCallback {
 
         /**
          * Called to indicate DRM info is available. Return a {@link DrmPreparationInfo} object that
@@ -3591,10 +3744,9 @@
          * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
          *         DRM initialization
          */
-        public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
-                @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) {
-            return null;
-        }
+        @Nullable
+        public abstract DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo);
 
         /**
          * Called to give the app the opportunity to configure DRM before the session is created.
@@ -3629,10 +3781,9 @@
          *         throwing an {@link RuntimeException} from this callback would trigger an
          *         {@link EventCallback#onError}.
          */
-        public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
-                @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) {
-            return new byte[0];
-        }
+        @NonNull
+        public abstract byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request);
 
         /**
          * Called to notify the client that {@code mp} is ready to decrypt DRM protected data source
@@ -3657,10 +3808,11 @@
     /**
      * Registers the callback to be invoked for various DRM events.
      *
+     * This is a synchronous call.
+     *
      * @param eventCallback the callback that will be run
      * @param executor the executor through which the callback should be invoked
      */
-    // This is a synchronous call.
     public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull DrmEventCallback eventCallback) {
         if (eventCallback == null) {
@@ -3677,8 +3829,9 @@
 
     /**
      * Clear the {@link DrmEventCallback}.
+     *
+     * This is a synchronous call.
      */
-    // This is a synchronous call.
     public void clearDrmEventCallback() {
         synchronized (mDrmEventCallbackLock) {
             mDrmEventCallback = null;
diff --git a/media/apex/java/android/media/MediaPlayer2Utils.java b/media/apex/java/android/media/MediaPlayer2Utils.java
index c6dee22..ac34260 100644
--- a/media/apex/java/android/media/MediaPlayer2Utils.java
+++ b/media/apex/java/android/media/MediaPlayer2Utils.java
@@ -36,6 +36,8 @@
                 .setSampleRate(sampleRate)
                 .setChannelMask(channelMask)
                 .build();
-        return AudioManager.isOffloadedPlaybackSupported(format);
+        //TODO MP2 needs to pass AudioAttributes for this query, instead of using default attr
+        return AudioManager.isOffloadedPlaybackSupported(format,
+                (new AudioAttributes.Builder()).build());
     }
 }
diff --git a/media/apex/java/android/media/ProxyDataSourceCallback.java b/media/apex/java/android/media/ProxyDataSourceCallback.java
new file mode 100644
index 0000000..14d3ce8
--- /dev/null
+++ b/media/apex/java/android/media/ProxyDataSourceCallback.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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.media;
+
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * A DataSourceCallback that is backed by a ParcelFileDescriptor.
+ */
+class ProxyDataSourceCallback extends DataSourceCallback {
+    private static final String TAG = "TestDataSourceCallback";
+
+    ParcelFileDescriptor mPFD;
+    FileDescriptor mFD;
+
+    ProxyDataSourceCallback(ParcelFileDescriptor pfd) throws IOException {
+        mPFD = pfd.dup();
+        mFD = mPFD.getFileDescriptor();
+    }
+
+    @Override
+    public synchronized int readAt(long position, byte[] buffer, int offset, int size)
+            throws IOException {
+        try {
+            Os.lseek(mFD, position, OsConstants.SEEK_SET);
+            int ret = Os.read(mFD, buffer, offset, size);
+            return (ret == 0) ? END_OF_STREAM : ret;
+        } catch (ErrnoException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public synchronized long getSize() throws IOException {
+        return mPFD.getStatSize();
+    }
+
+    @Override
+    public synchronized void close() {
+        try {
+            mPFD.close();
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to close the PFD.", e);
+        }
+    }
+}
+
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c926529..7cb5e00 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1489,13 +1489,18 @@
      * it does not indicate whether the resources necessary for the offloaded playback are
      * available at that instant.
      * @param format the audio format (codec, sample rate, channels) being checked.
+     * @param attributes the {@link AudioAttributes} to be used for playback
      * @return true if the given audio format can be offloaded.
      */
-    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
+            @NonNull AudioAttributes attributes) {
         if (format == null) {
-            throw new IllegalArgumentException("Illegal null AudioFormat");
+            throw new NullPointerException("Illegal null AudioFormat");
         }
-        return AudioSystem.isOffloadSupported(format);
+        if (attributes == null) {
+            throw new NullPointerException("Illegal null AudioAttributes");
+        }
+        return AudioSystem.isOffloadSupported(format, attributes);
     }
 
     //====================================================================
@@ -3308,7 +3313,8 @@
         try {
             MediaProjection projection = policy.getMediaProjection();
             String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
-                    policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController(),
+                    policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
+                    policy.isVolumeController(),
                     projection == null ? null : projection.getProjection());
             if (regId == null) {
                 return ERROR;
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 8051236..a7760a80 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1798,8 +1798,8 @@
      *
      * @return true if sucessful.
      */
-    public boolean setMicrophoneDirection(@DirectionMode int direction) {
-        return native_set_microphone_direction(direction) == AudioSystem.SUCCESS;
+    public boolean setPreferredMicrophoneDirection(@DirectionMode int direction) {
+        return native_set_preferred_microphone_direction(direction) == AudioSystem.SUCCESS;
     }
 
     /**
@@ -1810,10 +1810,11 @@
      * though 0 (no zoom) to 1 (maximum zoom).
      * @return true if sucessful.
      */
-    public boolean setMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom) {
+    public boolean setPreferredMicrophoneFieldDimension(
+                            @FloatRange(from = -1.0, to = 1.0) float zoom) {
         Preconditions.checkArgument(
                 zoom >= -1 && zoom <= 1, "Argument must fall between -1 & 1 (inclusive)");
-        return native_set_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
+        return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
     }
 
     //---------------------------------------------------------
@@ -1969,8 +1970,8 @@
 
     private native int native_getPortId();
 
-    private native int native_set_microphone_direction(int direction);
-    private native int native_set_microphone_field_dimension(float zoom);
+    private native int native_set_preferred_microphone_direction(int direction);
+    private native int native_set_preferred_microphone_field_dimension(float zoom);
 
     //---------------------------------------------------------
     // Utility methods
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a976d70..ad255fe 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1022,13 +1022,14 @@
 
     public static native float getStreamVolumeDB(int stream, int index, int device);
 
-    static boolean isOffloadSupported(@NonNull AudioFormat format) {
+    static boolean isOffloadSupported(@NonNull AudioFormat format, @NonNull AudioAttributes attr) {
         return native_is_offload_supported(format.getEncoding(), format.getSampleRate(),
-                format.getChannelMask(), format.getChannelIndexMask());
+                format.getChannelMask(), format.getChannelIndexMask(),
+                attr.getVolumeControlStream());
     }
 
     private static native boolean native_is_offload_supported(int encoding, int sampleRate,
-            int channelMask, int channelIndexMask);
+            int channelMask, int channelIndexMask, int streamType);
 
     public static native int getMicrophones(ArrayList<MicrophoneInfo> microphonesInfo);
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 41e059b..325e227 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -914,8 +914,9 @@
         /**
          * Sets whether this track will play through the offloaded audio path.
          * When set to true, at build time, the audio format will be checked against
-         * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
-         * used by this track is supported on the device's offload path (if any).
+         * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat,AudioAttributes)}
+         * to verify the audio format used by this track is supported on the device's offload
+         * path (if any).
          * <br>Offload is only supported for media audio streams, and therefore requires that
          * the usage be {@link AudioAttributes#USAGE_MEDIA}.
          * @param offload true to require the offload path for playback.
@@ -979,7 +980,7 @@
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload requires USAGE_MEDIA");
                 }
-                if (!AudioSystem.isOffloadSupported(mFormat)) {
+                if (!AudioSystem.isOffloadSupported(mFormat, mAttributes)) {
                     throw new UnsupportedOperationException(
                             "Cannot create AudioTrack, offload format not supported");
                 }
@@ -3177,7 +3178,8 @@
      * Registers a callback for the notification of stream events.
      * This callback can only be registered for instances operating in offloaded mode
      * (see {@link AudioTrack.Builder#setOffloadedPlayback(boolean)} and
-     * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} for more details).
+     * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat,AudioAttributes)} for
+     * more details).
      * @param executor {@link Executor} to handle the callbacks.
      * @param eventCallback the callback to receive the stream event notifications.
      */
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f2366d8..980cb04 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -196,6 +196,7 @@
 
     String registerAudioPolicy(in AudioPolicyConfig policyConfig,
             in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy,
+            boolean isTestFocusPolicy,
             boolean isVolumeController, in IMediaProjection projection);
 
     oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index aeb77cf..a08aec3 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -304,6 +304,11 @@
         }
 
         /**
+         * The SessionException has an unknown error code.
+         */
+        public static final int ERROR_UNKNOWN = 0;
+
+        /**
          * This indicates that apps using MediaDrm sessions are
          * temporarily exceeding the capacity of available crypto
          * resources. The app should retry the operation later.
@@ -547,6 +552,13 @@
          */
         public static final int STATUS_INTERNAL_ERROR = 4;
 
+        /**
+         * The key is not yet usable to decrypt media because the start
+         * time is in the future. The key will become usable when
+         * its start time is reached.
+         */
+        public static final int STATUS_USABLE_IN_FUTURE = 5;
+
         /** @hide */
         @IntDef({
             STATUS_USABLE,
@@ -554,6 +566,7 @@
             STATUS_OUTPUT_NOT_ALLOWED,
             STATUS_PENDING,
             STATUS_INTERNAL_ERROR,
+            STATUS_USABLE_IN_FUTURE,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface KeyStatusCode {}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index e7b4752..575a0bb 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1537,8 +1537,8 @@
      * @param direction Direction constant.
      * @return true if sucessful.
      */
-    public boolean setMicrophoneDirection(@DirectionMode int direction) {
-        return native_setMicrophoneDirection(direction) == 0;
+    public boolean setPreferredMicrophoneDirection(@DirectionMode int direction) {
+        return native_setPreferredMicrophoneDirection(direction) == 0;
     }
 
     /**
@@ -1549,14 +1549,15 @@
      * though 0 (no zoom) to 1 (maximum zoom).
      * @return true if sucessful.
      */
-    public boolean setMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom) {
+    public boolean setPreferredMicrophoneFieldDimension(
+                            @FloatRange(from = -1.0, to = 1.0) float zoom) {
         Preconditions.checkArgument(
                 zoom >= -1 && zoom <= 1, "Argument must fall between -1 & 1 (inclusive)");
-        return native_setMicrophoneFieldDimension(zoom) == 0;
+        return native_setPreferredMicrophoneFieldDimension(zoom) == 0;
     }
 
-    private native int native_setMicrophoneDirection(int direction);
-    private native int native_setMicrophoneFieldDimension(float zoom);
+    private native int native_setPreferredMicrophoneDirection(int direction);
+    private native int native_setPreferredMicrophoneFieldDimension(float zoom);
 
     //--------------------------------------------------------------------------
     // Implementation of AudioRecordingMonitor interface
diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java
index 2382da5..e4eec44 100644
--- a/media/java/android/media/MicrophoneDirection.java
+++ b/media/java/android/media/MicrophoneDirection.java
@@ -32,13 +32,21 @@
      */
     int MIC_DIRECTION_UNSPECIFIED = 0;
     /**
-     * Optimize capture for audio coming from the screen-side of the device.
+     * Optimize capture for audio coming from the side of the device facing the user.
+     * In the typical case, a device with a single screen, screen-side camera/microphone and
+     * non-screen-side camera/microphone, this will be the screen side (as in a "selfie").
+     * For a different device geometry, it is the side for which the expectation is to be
+     * facing the user.
      */
-    int MIC_DIRECTION_FRONT = 1;
+    int MIC_DIRECTION_TOWARDS_USER = 1;
     /**
-     * Optimize capture for audio coming from the side of the device opposite the screen.
+     * Optimize capture for audio coming from the side of the device pointing away from the user.
+     * In the typical case, a device with a single screen, screen-side camera/microphone and
+     * non-screen-side camera/microphone, this will be the non-screen side.
+     * For a different device geometry, it is the side for which the expectation is to be
+     * facing away from the user. This is the "taking a video of something else" case.
      */
-    int MIC_DIRECTION_BACK = 2;
+    int MIC_DIRECTION_AWAY_FROM_USER = 2;
     /**
      * Optimize capture for audio coming from an off-device microphone.
      */
@@ -47,8 +55,8 @@
     /** @hide */
     /*public*/ @IntDef({
             MIC_DIRECTION_UNSPECIFIED,
-            MIC_DIRECTION_FRONT,
-            MIC_DIRECTION_BACK,
+            MIC_DIRECTION_TOWARDS_USER,
+            MIC_DIRECTION_AWAY_FROM_USER,
             MIC_DIRECTION_EXTERNAL
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -58,18 +66,23 @@
      * which side of the device to optimize capture from. Typically used in conjunction with
      * the camera capturing video.
      *
+     * Usage would include specifying the audio capture to follow camera being used to capture
+     * video.
      * @param direction Direction constant.
      * @return true if sucessful.
      */
-    boolean setMicrophoneDirection(@DirectionMode int direction);
+    boolean setPreferredMicrophoneDirection(@DirectionMode int direction);
 
     /**
      * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
      * (for processing). The selected microphone is determined by the use-case for the stream.
      *
+     * Usage would include specifying the audio focus to follow the zoom specified for the camera
+     * being used to capture video.
+     *
      * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
      * though 0 (no zoom) to 1 (maximum zoom).
      * @return true if sucessful.
      */
-    boolean setMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom);
+    boolean setPreferredMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom);
 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 978583e..00f6013 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -75,6 +75,7 @@
     private String mRegistrationId;
     private AudioPolicyStatusListener mStatusListener;
     private boolean mIsFocusPolicy;
+    private boolean mIsTestFocusPolicy;
 
     /**
      * The list of AudioTrack instances created to inject audio into the associated mixes
@@ -121,6 +122,10 @@
     /** @hide */
     public boolean isFocusPolicy() { return mIsFocusPolicy; }
     /** @hide */
+    public boolean isTestFocusPolicy() {
+        return mIsTestFocusPolicy;
+    }
+    /** @hide */
     public boolean isVolumeController() { return mVolCb != null; }
     /** @hide */
     public @Nullable MediaProjection getMediaProjection() {
@@ -128,10 +133,11 @@
     }
 
     /**
-     * The parameter is guaranteed non-null through the Builder
+     * The parameters are guaranteed non-null through the Builder
      */
     private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper,
-            AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, boolean isFocusPolicy,
+            AudioPolicyFocusListener fl, AudioPolicyStatusListener sl,
+            boolean isFocusPolicy, boolean isTestFocusPolicy,
             AudioPolicyVolumeCallback vc, @Nullable MediaProjection projection) {
         mConfig = config;
         mStatus = POLICY_STATUS_UNREGISTERED;
@@ -148,6 +154,7 @@
         mFocusListener = fl;
         mStatusListener = sl;
         mIsFocusPolicy = isFocusPolicy;
+        mIsTestFocusPolicy = isTestFocusPolicy;
         mVolCb = vc;
         mProjection = projection;
     }
@@ -163,6 +170,7 @@
         private AudioPolicyFocusListener mFocusListener;
         private AudioPolicyStatusListener mStatusListener;
         private boolean mIsFocusPolicy = false;
+        private boolean mIsTestFocusPolicy = false;
         private AudioPolicyVolumeCallback mVolCb;
         private MediaProjection mProjection;
 
@@ -181,6 +189,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
+        @NonNull
         public Builder addMix(@NonNull AudioMix mix) throws IllegalArgumentException {
             if (mix == null) {
                 throw new IllegalArgumentException("Illegal null AudioMix argument");
@@ -195,6 +204,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
+        @NonNull
         public Builder setLooper(@NonNull Looper looper) throws IllegalArgumentException {
             if (looper == null) {
                 throw new IllegalArgumentException("Illegal null Looper argument");
@@ -220,12 +230,28 @@
          * @param enforce true if the policy will govern audio focus decisions.
          * @return the same Builder instance.
          */
+        @NonNull
         public Builder setIsAudioFocusPolicy(boolean isFocusPolicy) {
             mIsFocusPolicy = isFocusPolicy;
             return this;
         }
 
         /**
+         * Test method to declare whether this audio focus policy is for test purposes only.
+         * Having a test policy registered will disable the current focus policy and replace it
+         * with this test policy. When unregistered, the previous focus policy will be restored.
+         * <p>A value of <code>true</code> will be ignored if the AudioPolicy is not also
+         * focus policy.
+         * @param isTestFocusPolicy true if the focus policy to register is for testing purposes.
+         * @return the same Builder instance
+         */
+        @NonNull
+        public Builder setIsTestFocusPolicy(boolean isTestFocusPolicy) {
+            mIsTestFocusPolicy = isTestFocusPolicy;
+            return this;
+        }
+
+        /**
          * Sets the audio policy status listener.
          * @param l a {@link AudioPolicy.AudioPolicyStatusListener}
          */
@@ -240,6 +266,7 @@
          * @param vc
          * @return the same Builder instance.
          */
+        @NonNull
         public Builder setAudioPolicyVolumeCallback(@NonNull AudioPolicyVolumeCallback vc) {
             if (vc == null) {
                 throw new IllegalArgumentException("Invalid null volume callback");
@@ -256,6 +283,7 @@
          *
          * @hide
          */
+        @NonNull
         public Builder setMediaProjection(@NonNull MediaProjection projection) {
             if (projection == null) {
                 throw new IllegalArgumentException("Invalid null volume callback");
@@ -273,6 +301,7 @@
          *     {@link AudioPolicy.AudioPolicyStatusListener} but the policy was configured
          *     as an audio focus policy with {@link #setIsAudioFocusPolicy(boolean)}.
          */
+        @NonNull
         public AudioPolicy build() {
             if (mStatusListener != null) {
                 // the AudioPolicy status listener includes updates on each mix activity state
@@ -285,7 +314,8 @@
                         + "an AudioPolicyFocusListener");
             }
             return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
-                    mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb, mProjection);
+                    mFocusListener, mStatusListener, mIsFocusPolicy, mIsTestFocusPolicy,
+                    mVolCb, mProjection);
         }
     }
 
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
new file mode 100644
index 0000000..7e7335d
--- /dev/null
+++ b/media/java/android/media/projection/OWNERS
@@ -0,0 +1 @@
+michaelwr@google.com
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cbc6c9d..080094c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -27,12 +27,15 @@
 import android.media.AudioAttributes;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
@@ -40,6 +43,10 @@
 import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -116,12 +123,21 @@
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
-    private final MediaSessionEngine mImpl;
+    private final Object mLock = new Object();
     private final int mMaxBitmapSize;
 
+    private final Token mSessionToken;
+    private final MediaController mController;
+    private final ISession mBinder;
+    private final SessionCallbackLink mCbStub;
+
     // Do not change the name of mCallback. Support lib accesses this by using reflection.
     @UnsupportedAppUsage
-    private Object mCallback;
+    private CallbackMessageHandler mCallback;
+    private VolumeProvider mVolumeProvider;
+    private PlaybackState mPlaybackState;
+
+    private boolean mActive = false;
 
     /**
      * Creates a new session. The session will automatically be registered with
@@ -160,14 +176,15 @@
         if (TextUtils.isEmpty(tag)) {
             throw new IllegalArgumentException("tag cannot be null or empty");
         }
+        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
+        mCbStub = new SessionCallbackLink(context, this);
         MediaSessionManager manager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
-            SessionCallbackLink cbLink = new SessionCallbackLink(context);
-            ISession binder = manager.createSession(cbLink, tag, sessionInfo);
-            mImpl = new MediaSessionEngine(context, binder, cbLink);
-            mMaxBitmapSize = context.getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
+            mBinder = manager.createSession(mCbStub, tag, sessionInfo);
+            mSessionToken = new Token(mBinder.getController());
+            mController = new MediaController(context, mSessionToken);
         } catch (RemoteException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
@@ -183,8 +200,7 @@
      * @param callback The callback object
      */
     public void setCallback(@Nullable Callback callback) {
-        mCallback = callback == null ? null : new Object();
-        mImpl.setCallback(callback);
+        setCallback(callback, null);
     }
 
     /**
@@ -197,8 +213,24 @@
      * @param handler The handler that events should be posted on.
      */
     public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
-        mCallback = callback == null ? null : new Object();
-        mImpl.setCallback(callback, handler);
+        synchronized (mLock) {
+            if (mCallback != null) {
+                // We're updating the callback, clear the session from the old one.
+                mCallback.mCallback.mSession = null;
+                mCallback.removeCallbacksAndMessages(null);
+            }
+            if (callback == null) {
+                mCallback = null;
+                return;
+            }
+            if (handler == null) {
+                handler = new Handler();
+            }
+            callback.mSession = this;
+            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
+                    callback);
+            mCallback = msgHandler;
+        }
     }
 
     /**
@@ -209,7 +241,11 @@
      * @param pi The intent to launch to show UI for this Session.
      */
     public void setSessionActivity(@Nullable PendingIntent pi) {
-        mImpl.setSessionActivity(pi);
+        try {
+            mBinder.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
+        }
     }
 
     /**
@@ -221,7 +257,11 @@
      * @param mbr The {@link PendingIntent} to send the media button event to.
      */
     public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        mImpl.setMediaButtonReceiver(mbr);
+        try {
+            mBinder.setMediaButtonReceiver(mbr);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+        }
     }
 
     /**
@@ -230,7 +270,11 @@
      * @param flags The flags to set for this session.
      */
     public void setFlags(@SessionFlags int flags) {
-        mImpl.setFlags(flags);
+        try {
+            mBinder.setFlags(flags);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setFlags.", e);
+        }
     }
 
     /**
@@ -245,7 +289,14 @@
      * @param attributes The {@link AudioAttributes} for this session's audio.
      */
     public void setPlaybackToLocal(AudioAttributes attributes) {
-        mImpl.setPlaybackToLocal(attributes);
+        if (attributes == null) {
+            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
+        }
+        try {
+            mBinder.setPlaybackToLocal(attributes);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
+        }
     }
 
     /**
@@ -260,7 +311,26 @@
      *            not be null.
      */
     public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
-        mImpl.setPlaybackToRemote(volumeProvider);
+        if (volumeProvider == null) {
+            throw new IllegalArgumentException("volumeProvider may not be null!");
+        }
+        synchronized (mLock) {
+            mVolumeProvider = volumeProvider;
+        }
+        volumeProvider.setCallback(new VolumeProvider.Callback() {
+            @Override
+            public void onVolumeChanged(VolumeProvider volumeProvider) {
+                notifyRemoteVolumeChanged(volumeProvider);
+            }
+        });
+
+        try {
+            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+                    volumeProvider.getMaxVolume());
+            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
+        }
     }
 
     /**
@@ -272,7 +342,15 @@
      * @param active Whether this session is active or not.
      */
     public void setActive(boolean active) {
-        mImpl.setActive(active);
+        if (mActive == active) {
+            return;
+        }
+        try {
+            mBinder.setActive(active);
+            mActive = active;
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setActive.", e);
+        }
     }
 
     /**
@@ -281,7 +359,7 @@
      * @return True if the session is active, false otherwise.
      */
     public boolean isActive() {
-        return mImpl.isActive();
+        return mActive;
     }
 
     /**
@@ -293,7 +371,14 @@
      * @param extras Any extras included with the event
      */
     public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        mImpl.sendSessionEvent(event, extras);
+        if (TextUtils.isEmpty(event)) {
+            throw new IllegalArgumentException("event cannot be null or empty");
+        }
+        try {
+            mBinder.sendEvent(event, extras);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error sending event", e);
+        }
     }
 
     /**
@@ -302,7 +387,11 @@
      * but it must be released if your activity or service is being destroyed.
      */
     public void release() {
-        mImpl.close();
+        try {
+            mBinder.destroySession();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error releasing session: ", e);
+        }
     }
 
     /**
@@ -314,7 +403,7 @@
      *         session
      */
     public @NonNull Token getSessionToken() {
-        return mImpl.getSessionToken();
+        return mSessionToken;
     }
 
     /**
@@ -324,7 +413,7 @@
      * @return A controller for this session.
      */
     public @NonNull MediaController getController() {
-        return mImpl.getController();
+        return mController;
     }
 
     /**
@@ -333,7 +422,12 @@
      * @param state The current state of playback
      */
     public void setPlaybackState(@Nullable PlaybackState state) {
-        mImpl.setPlaybackState(state);
+        mPlaybackState = state;
+        try {
+            mBinder.setPlaybackState(state);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
     }
 
     /**
@@ -345,10 +439,24 @@
      * @see android.media.MediaMetadata.Builder#putBitmap
      */
     public void setMetadata(@Nullable MediaMetadata metadata) {
+        long duration = -1;
+        int fields = 0;
+        MediaDescription description = null;
         if (metadata != null) {
-            metadata = new MediaMetadata.Builder(metadata, mMaxBitmapSize).build();
+            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+            if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+                duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+            }
+            fields = metadata.size();
+            description = metadata.getDescription();
         }
-        mImpl.setMetadata(metadata);
+        String metadataDescription = "size=" + fields + ", description=" + description;
+
+        try {
+            mBinder.setMetadata(metadata, duration, metadataDescription);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
     }
 
     /**
@@ -363,7 +471,11 @@
      * @param queue A list of items in the play queue.
      */
     public void setQueue(@Nullable List<QueueItem> queue) {
-        mImpl.setQueue(queue);
+        try {
+            mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setQueue.", e);
+        }
     }
 
     /**
@@ -374,7 +486,11 @@
      * @param title The title of the play queue.
      */
     public void setQueueTitle(@Nullable CharSequence title) {
-        mImpl.setQueueTitle(title);
+        try {
+            mBinder.setQueueTitle(title);
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setQueueTitle.", e);
+        }
     }
 
     /**
@@ -391,7 +507,11 @@
      * </ul>
      */
     public void setRatingType(@Rating.Style int type) {
-        mImpl.setRatingType(type);
+        try {
+            mBinder.setRatingType(type);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in setRatingType.", e);
+        }
     }
 
     /**
@@ -402,7 +522,11 @@
      * @param extras The extras associated with the {@link MediaSession}.
      */
     public void setExtras(@Nullable Bundle extras) {
-        mImpl.setExtras(extras);
+        try {
+            mBinder.setExtras(extras);
+        } catch (RemoteException e) {
+            Log.wtf("Dead object in setExtras.", e);
+        }
     }
 
     /**
@@ -414,7 +538,31 @@
      * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
      */
     public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        return mImpl.getCurrentControllerInfo();
+        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
+            throw new IllegalStateException(
+                    "This should be called inside of MediaSession.Callback methods");
+        }
+        return mCallback.mCurrentControllerInfo;
+    }
+
+    /**
+     * Notify the system that the remote volume changed.
+     *
+     * @param provider The provider that is handling volume changes.
+     * @hide
+     */
+    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
+        synchronized (mLock) {
+            if (provider == null || provider != mVolumeProvider) {
+                Log.w(TAG, "Received update from stale volume provider");
+                return;
+            }
+        }
+        try {
+            mBinder.setCurrentVolume(provider.getCurrentVolume());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in notifyVolumeChanged", e);
+        }
     }
 
     /**
@@ -426,7 +574,10 @@
      */
     @UnsupportedAppUsage
     public String getCallingPackage() {
-        return mImpl.getCallingPackage();
+        if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
+            return mCallback.mCurrentControllerInfo.getPackageName();
+        }
+        return null;
     }
 
     /**
@@ -435,7 +586,130 @@
      * @hide
      */
     public static boolean isActiveState(int state) {
-        return MediaSessionEngine.isActiveState(state);
+        switch (state) {
+            case PlaybackState.STATE_FAST_FORWARDING:
+            case PlaybackState.STATE_REWINDING:
+            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+            case PlaybackState.STATE_SKIPPING_TO_NEXT:
+            case PlaybackState.STATE_BUFFERING:
+            case PlaybackState.STATE_CONNECTING:
+            case PlaybackState.STATE_PLAYING:
+                return true;
+        }
+        return false;
+    }
+
+    void dispatchPrepare(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
+    }
+
+    void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+    }
+
+    void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+    }
+
+    void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+    }
+
+    void dispatchPlay(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
+    }
+
+    void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
+    }
+
+    void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
+    }
+
+    void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+    }
+
+    void dispatchSkipToItem(RemoteUserInfo caller, long id) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
+    }
+
+    void dispatchPause(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
+    }
+
+    void dispatchStop(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
+    }
+
+    void dispatchNext(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
+    }
+
+    void dispatchPrevious(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
+    }
+
+    void dispatchFastForward(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
+    }
+
+    void dispatchRewind(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
+    }
+
+    void dispatchSeekTo(RemoteUserInfo caller, long pos) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
+    }
+
+    void dispatchRate(RemoteUserInfo caller, Rating rating) {
+        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
+    }
+
+    void dispatchSetPlaybackSpeed(RemoteUserInfo caller, float speed) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SET_PLAYBACK_SPEED, speed, null);
+    }
+
+    void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
+        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
+    }
+
+    void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
+        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
+    }
+
+    void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
+            long delay) {
+        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+                mediaButtonIntent, null, delay);
+    }
+
+    void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
+        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
+    }
+
+    void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
+    }
+
+    void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
+            ResultReceiver resultCb) {
+        Command cmd = new Command(command, args, resultCb);
+        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
+    }
+
+    void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
+        postToCallbackDelayed(caller, what, obj, data, 0);
+    }
+
+    void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
+            long delay) {
+        synchronized (mLock) {
+            if (mCallback != null) {
+                mCallback.post(caller, what, obj, data, delay);
+            }
+        }
     }
 
     /**
@@ -534,7 +808,9 @@
      */
     public abstract static class Callback {
 
-        MediaSessionEngine.MediaButtonEventDelegate mMediaButtonEventDelegate;
+        private MediaSession mSession;
+        private CallbackMessageHandler mHandler;
+        private boolean mMediaPlayPauseKeyPending;
 
         public Callback() {
         }
@@ -566,12 +842,110 @@
          * @return True if the event was handled, false otherwise.
          */
         public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
-            if (mMediaButtonEventDelegate != null) {
-                return mMediaButtonEventDelegate.onMediaButtonIntent(mediaButtonIntent);
+            if (mSession != null && mHandler != null
+                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
+                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
+                    PlaybackState state = mSession.mPlaybackState;
+                    long validActions = state == null ? 0 : state.getActions();
+                    switch (ke.getKeyCode()) {
+                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                        case KeyEvent.KEYCODE_HEADSETHOOK:
+                            if (ke.getRepeatCount() > 0) {
+                                // Consider long-press as a single tap.
+                                handleMediaPlayPauseKeySingleTapIfPending();
+                            } else if (mMediaPlayPauseKeyPending) {
+                                // Consider double tap as the next.
+                                mHandler.removeMessages(CallbackMessageHandler
+                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
+                                mMediaPlayPauseKeyPending = false;
+                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+                                    onSkipToNext();
+                                }
+                            } else {
+                                mMediaPlayPauseKeyPending = true;
+                                mSession.dispatchMediaButtonDelayed(
+                                        mSession.getCurrentControllerInfo(),
+                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
+                            }
+                            return true;
+                        default:
+                            // If another key is pressed within double tap timeout, consider the
+                            // pending play/pause as a single tap to handle media keys in order.
+                            handleMediaPlayPauseKeySingleTapIfPending();
+                            break;
+                    }
+
+                    switch (ke.getKeyCode()) {
+                        case KeyEvent.KEYCODE_MEDIA_PLAY:
+                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
+                                onPlay();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
+                                onPause();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_NEXT:
+                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+                                onSkipToNext();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
+                                onSkipToPrevious();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_STOP:
+                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
+                                onStop();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
+                                onFastForward();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_REWIND:
+                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
+                                onRewind();
+                                return true;
+                            }
+                            break;
+                    }
+                }
             }
             return false;
         }
 
+        private void handleMediaPlayPauseKeySingleTapIfPending() {
+            if (!mMediaPlayPauseKeyPending) {
+                return;
+            }
+            mMediaPlayPauseKeyPending = false;
+            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
+            PlaybackState state = mSession.mPlaybackState;
+            long validActions = state == null ? 0 : state.getActions();
+            boolean isPlaying = state != null
+                    && state.getState() == PlaybackState.STATE_PLAYING;
+            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
+                    | PlaybackState.ACTION_PLAY)) != 0;
+            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
+                    | PlaybackState.ACTION_PAUSE)) != 0;
+            if (isPlaying && canPause) {
+                onPause();
+            } else if (!isPlaying && canPlay) {
+                onPlay();
+            }
+        }
+
         /**
          * Override to handle requests to prepare playback. During the preparation, a session should
          * not hold audio focus in order to allow other sessions play seamlessly. The state of
@@ -727,14 +1101,6 @@
          */
         public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
         }
-
-        /**
-         * @hide
-         */
-        public void onSetMediaButtonEventDelegate(
-                @NonNull MediaSessionEngine.MediaButtonEventDelegate delegate) {
-            mMediaButtonEventDelegate = delegate;
-        }
     }
 
     /**
@@ -747,7 +1113,7 @@
          */
         public static final int UNKNOWN_ID = -1;
 
-        private final MediaSessionEngine.QueueItem mImpl;
+        private final MediaDescription mDescription;
         @UnsupportedAppUsage
         private final long mId;
 
@@ -759,32 +1125,39 @@
          *            play queue and cannot be {@link #UNKNOWN_ID}.
          */
         public QueueItem(MediaDescription description, long id) {
-            mImpl = new MediaSessionEngine.QueueItem(description, id);
+            if (description == null) {
+                throw new IllegalArgumentException("Description cannot be null.");
+            }
+            if (id == UNKNOWN_ID) {
+                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
+            }
+            mDescription = description;
             mId = id;
         }
 
         private QueueItem(Parcel in) {
-            mImpl = new MediaSessionEngine.QueueItem(in);
-            mId = mImpl.getQueueId();
+            mDescription = MediaDescription.CREATOR.createFromParcel(in);
+            mId = in.readLong();
         }
 
         /**
          * Get the description for this item.
          */
         public MediaDescription getDescription() {
-            return mImpl.getDescription();
+            return mDescription;
         }
 
         /**
          * Get the queue id for this item.
          */
         public long getQueueId() {
-            return mImpl.getQueueId();
+            return mId;
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            mImpl.writeToParcel(dest, flags);
+            mDescription.writeToParcel(dest, flags);
+            dest.writeLong(mId);
         }
 
         @Override
@@ -795,20 +1168,21 @@
         public static final @android.annotation.NonNull Creator<MediaSession.QueueItem> CREATOR =
                 new Creator<MediaSession.QueueItem>() {
 
-            @Override
-            public MediaSession.QueueItem createFromParcel(Parcel p) {
-                return new MediaSession.QueueItem(p);
-            }
+                    @Override
+                    public MediaSession.QueueItem createFromParcel(Parcel p) {
+                        return new MediaSession.QueueItem(p);
+                    }
 
-            @Override
-            public MediaSession.QueueItem[] newArray(int size) {
-                return new MediaSession.QueueItem[size];
-            }
-        };
+                    @Override
+                    public MediaSession.QueueItem[] newArray(int size) {
+                        return new MediaSession.QueueItem[size];
+                    }
+                };
 
         @Override
         public String toString() {
-            return mImpl.toString();
+            return "MediaSession.QueueItem {" + "Description=" + mDescription + ", Id=" + mId
+                    + " }";
         }
 
         @Override
@@ -821,7 +1195,171 @@
                 return false;
             }
 
-            return mImpl.equals(((QueueItem) o).mImpl);
+            final QueueItem item = (QueueItem) o;
+            if (mId != item.mId) {
+                return false;
+            }
+
+            if (!Objects.equals(mDescription, item.mDescription)) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    private static final class Command {
+        public final String command;
+        public final Bundle extras;
+        public final ResultReceiver stub;
+
+        Command(String command, Bundle extras, ResultReceiver stub) {
+            this.command = command;
+            this.extras = extras;
+            this.stub = stub;
+        }
+    }
+
+    private class CallbackMessageHandler extends Handler {
+        private static final int MSG_COMMAND = 1;
+        private static final int MSG_MEDIA_BUTTON = 2;
+        private static final int MSG_PREPARE = 3;
+        private static final int MSG_PREPARE_MEDIA_ID = 4;
+        private static final int MSG_PREPARE_SEARCH = 5;
+        private static final int MSG_PREPARE_URI = 6;
+        private static final int MSG_PLAY = 7;
+        private static final int MSG_PLAY_MEDIA_ID = 8;
+        private static final int MSG_PLAY_SEARCH = 9;
+        private static final int MSG_PLAY_URI = 10;
+        private static final int MSG_SKIP_TO_ITEM = 11;
+        private static final int MSG_PAUSE = 12;
+        private static final int MSG_STOP = 13;
+        private static final int MSG_NEXT = 14;
+        private static final int MSG_PREVIOUS = 15;
+        private static final int MSG_FAST_FORWARD = 16;
+        private static final int MSG_REWIND = 17;
+        private static final int MSG_SEEK_TO = 18;
+        private static final int MSG_RATE = 19;
+        private static final int MSG_SET_PLAYBACK_SPEED = 20;
+        private static final int MSG_CUSTOM_ACTION = 21;
+        private static final int MSG_ADJUST_VOLUME = 22;
+        private static final int MSG_SET_VOLUME = 23;
+        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 24;
+
+        private MediaSession.Callback mCallback;
+        private RemoteUserInfo mCurrentControllerInfo;
+
+        CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
+            super(looper);
+            mCallback = callback;
+            mCallback.mHandler = this;
+        }
+
+        void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
+            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
+            Message msg = obtainMessage(what, objWithCaller);
+            msg.setAsynchronous(true);
+            msg.setData(data);
+            if (delayMs > 0) {
+                sendMessageDelayed(msg, delayMs);
+            } else {
+                sendMessage(msg);
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
+
+            VolumeProvider vp;
+            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
+
+            switch (msg.what) {
+                case MSG_COMMAND:
+                    Command cmd = (Command) obj;
+                    mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
+                    break;
+                case MSG_MEDIA_BUTTON:
+                    mCallback.onMediaButtonEvent((Intent) obj);
+                    break;
+                case MSG_PREPARE:
+                    mCallback.onPrepare();
+                    break;
+                case MSG_PREPARE_MEDIA_ID:
+                    mCallback.onPrepareFromMediaId((String) obj, msg.getData());
+                    break;
+                case MSG_PREPARE_SEARCH:
+                    mCallback.onPrepareFromSearch((String) obj, msg.getData());
+                    break;
+                case MSG_PREPARE_URI:
+                    mCallback.onPrepareFromUri((Uri) obj, msg.getData());
+                    break;
+                case MSG_PLAY:
+                    mCallback.onPlay();
+                    break;
+                case MSG_PLAY_MEDIA_ID:
+                    mCallback.onPlayFromMediaId((String) obj, msg.getData());
+                    break;
+                case MSG_PLAY_SEARCH:
+                    mCallback.onPlayFromSearch((String) obj, msg.getData());
+                    break;
+                case MSG_PLAY_URI:
+                    mCallback.onPlayFromUri((Uri) obj, msg.getData());
+                    break;
+                case MSG_SKIP_TO_ITEM:
+                    mCallback.onSkipToQueueItem((Long) obj);
+                    break;
+                case MSG_PAUSE:
+                    mCallback.onPause();
+                    break;
+                case MSG_STOP:
+                    mCallback.onStop();
+                    break;
+                case MSG_NEXT:
+                    mCallback.onSkipToNext();
+                    break;
+                case MSG_PREVIOUS:
+                    mCallback.onSkipToPrevious();
+                    break;
+                case MSG_FAST_FORWARD:
+                    mCallback.onFastForward();
+                    break;
+                case MSG_REWIND:
+                    mCallback.onRewind();
+                    break;
+                case MSG_SEEK_TO:
+                    mCallback.onSeekTo((Long) obj);
+                    break;
+                case MSG_RATE:
+                    mCallback.onSetRating((Rating) obj);
+                    break;
+                case MSG_SET_PLAYBACK_SPEED:
+                    mCallback.onSetPlaybackSpeed((Float) obj);
+                    break;
+                case MSG_CUSTOM_ACTION:
+                    mCallback.onCustomAction((String) obj, msg.getData());
+                    break;
+                case MSG_ADJUST_VOLUME:
+                    synchronized (mLock) {
+                        vp = mVolumeProvider;
+                    }
+                    if (vp != null) {
+                        vp.onAdjustVolume((int) obj);
+                    }
+                    break;
+                case MSG_SET_VOLUME:
+                    synchronized (mLock) {
+                        vp = mVolumeProvider;
+                    }
+                    if (vp != null) {
+                        vp.onSetVolumeTo((int) obj);
+                    }
+                    break;
+                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
+                    mCallback.handleMediaPlayPauseKeySingleTapIfPending();
+                    break;
+            }
+            mCurrentControllerInfo = null;
         }
     }
 }
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
deleted file mode 100644
index 7c5243a..0000000
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
- * Copyright 2019 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.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioAttributes;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * @hide
- */
-public final class MediaSessionEngine implements AutoCloseable {
-    private static final String TAG = "MediaSession";
-
-    private final Object mLock = new Object();
-
-    private final MediaSession.Token mSessionToken;
-    private final MediaController mController;
-    private final ISession mBinder;
-
-    private CallbackMessageHandler mCallbackHandler;
-    private VolumeProvider mVolumeProvider;
-    private PlaybackState mPlaybackState;
-
-    private boolean mActive = false;
-
-    /**
-     * Creates a new session. The session will automatically be registered with
-     * the system but will not be published until {@link #setActive(boolean)
-     * setActive(true)} is called. You must call {@link #close()} when
-     * finished with the session.
-     *
-     * @param context The context to use to create the session.
-     * @param binder A session binder
-     */
-    public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder,
-            @NonNull SessionCallbackLink cbLink) throws RemoteException {
-        mBinder = binder;
-
-        cbLink.setSessionEngine(this);
-        mSessionToken = new MediaSession.Token(mBinder.getController());
-        mController = new MediaController(context, mSessionToken);
-    }
-
-    /**
-     * Set the callback to receive updates for the MediaSession. This includes
-     * media button events and transport controls. The caller's thread will be
-     * used to post updates.
-     * <p>
-     * Set the callback to null to stop receiving updates.
-     *
-     * @param callback The callback object
-     */
-    public void setCallback(@Nullable MediaSession.Callback callback) {
-        setCallback(callback, new Handler());
-    }
-
-    /**
-     * Set the callback to receive updates for the MediaSession. This includes
-     * media button events and transport controls.
-     * <p>
-     * Set the callback to null to stop receiving updates.
-     *
-     * @param callback The callback to receive updates on.
-     * @param handler The handler that events should be posted on.
-     */
-    public void setCallback(@Nullable MediaSession.Callback callback, @NonNull Handler handler) {
-        setCallbackInternal(callback == null ? null : new CallbackWrapper(callback), handler);
-    }
-
-    private void setCallbackInternal(CallbackWrapper callback, Handler handler) {
-        synchronized (mLock) {
-            if (mCallbackHandler != null) {
-                // We're updating the callback, clear the session from the old one.
-                mCallbackHandler.mCallbackWrapper.mSessionImpl = null;
-                mCallbackHandler.removeCallbacksAndMessages(null);
-            }
-            if (callback == null) {
-                mCallbackHandler = null;
-                return;
-            }
-            callback.mSessionImpl = this;
-            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
-                    callback);
-            mCallbackHandler = msgHandler;
-        }
-    }
-
-    /**
-     * Set an intent for launching UI for this Session. This can be used as a
-     * quick link to an ongoing media screen. The intent should be for an
-     * activity that may be started using {@link Activity#startActivity(Intent)}.
-     *
-     * @param pi The intent to launch to show UI for this Session.
-     */
-    public void setSessionActivity(@Nullable PendingIntent pi) {
-        try {
-            mBinder.setLaunchPendingIntent(pi);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
-        }
-    }
-
-    /**
-     * Set a pending intent for your media button receiver to allow restarting
-     * playback after the session has been stopped. If your app is started in
-     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
-     * the pending intent.
-     *
-     * @param mbr The {@link PendingIntent} to send the media button event to.
-     */
-    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        try {
-            mBinder.setMediaButtonReceiver(mbr);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
-        }
-    }
-
-    /**
-     * Set any flags for the session.
-     *
-     * @param flags The flags to set for this session.
-     */
-    public void setFlags(int flags) {
-        try {
-            mBinder.setFlags(flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setFlags.", e);
-        }
-    }
-
-    /**
-     * Set the attributes for this session's audio. This will affect the
-     * system's volume handling for this session. If
-     * {@link #setPlaybackToRemote} was previously called it will stop receiving
-     * volume commands and the system will begin sending volume changes to the
-     * appropriate stream.
-     * <p>
-     * By default sessions use attributes for media.
-     *
-     * @param attributes The {@link AudioAttributes} for this session's audio.
-     */
-    public void setPlaybackToLocal(AudioAttributes attributes) {
-        if (attributes == null) {
-            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
-        }
-        try {
-            mBinder.setPlaybackToLocal(attributes);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
-        }
-    }
-
-    /**
-     * Configure this session to use remote volume handling. This must be called
-     * to receive volume button events, otherwise the system will adjust the
-     * appropriate stream volume for this session. If
-     * {@link #setPlaybackToLocal} was previously called the system will stop
-     * handling volume changes for this session and pass them to the volume
-     * provider instead.
-     *
-     * @param volumeProvider The provider that will handle volume changes. May
-     *            not be null.
-     */
-    public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
-        if (volumeProvider == null) {
-            throw new IllegalArgumentException("volumeProvider may not be null!");
-        }
-        synchronized (mLock) {
-            mVolumeProvider = volumeProvider;
-        }
-        volumeProvider.setCallback(new VolumeProvider.Callback() {
-            @Override
-            public void onVolumeChanged(VolumeProvider volumeProvider) {
-                notifyRemoteVolumeChanged(volumeProvider);
-            }
-        });
-
-        try {
-            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
-                    volumeProvider.getMaxVolume());
-            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
-        }
-    }
-
-    /**
-     * Set if this session is currently active and ready to receive commands. If
-     * set to false your session's controller may not be discoverable. You must
-     * set the session to active before it can start receiving media button
-     * events or transport commands.
-     *
-     * @param active Whether this session is active or not.
-     */
-    public void setActive(boolean active) {
-        if (mActive == active) {
-            return;
-        }
-        try {
-            mBinder.setActive(active);
-            mActive = active;
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setActive.", e);
-        }
-    }
-
-    /**
-     * Get the current active state of this session.
-     *
-     * @return True if the session is active, false otherwise.
-     */
-    public boolean isActive() {
-        return mActive;
-    }
-
-    /**
-     * Send a proprietary event to all MediaControllers listening to this
-     * Session. It's up to the Controller/Session owner to determine the meaning
-     * of any events.
-     *
-     * @param event The name of the event to send
-     * @param extras Any extras included with the event
-     */
-    public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        if (TextUtils.isEmpty(event)) {
-            throw new IllegalArgumentException("event cannot be null or empty");
-        }
-        try {
-            mBinder.sendEvent(event, extras);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error sending event", e);
-        }
-    }
-
-    /**
-     * This must be called when an app has finished performing playback. If
-     * playback is expected to start again shortly the session can be left open,
-     * but it must be released if your activity or service is being destroyed.
-     */
-    public void close() {
-        try {
-            mBinder.destroySession();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error releasing session: ", e);
-        }
-    }
-
-    /**
-     * Retrieve a token object that can be used by apps to create a
-     * {@link MediaController} for interacting with this session. The owner of
-     * the session is responsible for deciding how to distribute these tokens.
-     *
-     * @return A token that can be used to create a MediaController for this
-     *         session
-     */
-    public @NonNull MediaSession.Token getSessionToken() {
-        return mSessionToken;
-    }
-
-    /**
-     * Get a controller for this session. This is a convenience method to avoid
-     * having to cache your own controller in process.
-     *
-     * @return A controller for this session.
-     */
-    public @NonNull MediaController getController() {
-        return mController;
-    }
-
-    /**
-     * Update the current playback state.
-     *
-     * @param state The current state of playback
-     */
-    public void setPlaybackState(@Nullable PlaybackState state) {
-        mPlaybackState = state;
-        try {
-            mBinder.setPlaybackState(state);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * Update the current metadata. New metadata can be created using
-     * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
-     * the size of the bitmap to replace large bitmaps with a scaled down copy.
-     *
-     * @param metadata The new metadata
-     * @see android.media.MediaMetadata.Builder#putBitmap
-     */
-    public void setMetadata(@Nullable MediaMetadata metadata) {
-        long duration = -1;
-        int fields = 0;
-        MediaDescription description = null;
-        if (metadata != null) {
-            if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
-                duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            }
-            fields = metadata.size();
-            description = metadata.getDescription();
-        }
-        String metadataDescription = "size=" + fields + ", description=" + description;
-
-        try {
-            mBinder.setMetadata(metadata, duration, metadataDescription);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * Update the list of items in the play queue. It is an ordered list and
-     * should contain the current item, and previous or upcoming items if they
-     * exist. Specify null if there is no current play queue.
-     * <p>
-     * The queue should be of reasonable size. If the play queue is unbounded
-     * within your app, it is better to send a reasonable amount in a sliding
-     * window instead.
-     *
-     * @param queue A list of items in the play queue.
-     */
-    public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
-        try {
-            mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueue.", e);
-        }
-    }
-
-    /**
-     * Set the title of the play queue. The UI should display this title along
-     * with the play queue itself.
-     * e.g. "Play Queue", "Now Playing", or an album name.
-     *
-     * @param title The title of the play queue.
-     */
-    public void setQueueTitle(@Nullable CharSequence title) {
-        try {
-            mBinder.setQueueTitle(title);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueueTitle.", e);
-        }
-    }
-
-    /**
-     * Set the style of rating used by this session. Apps trying to set the
-     * rating should use this style. Must be one of the following:
-     * <ul>
-     * <li>{@link Rating#RATING_NONE}</li>
-     * <li>{@link Rating#RATING_3_STARS}</li>
-     * <li>{@link Rating#RATING_4_STARS}</li>
-     * <li>{@link Rating#RATING_5_STARS}</li>
-     * <li>{@link Rating#RATING_HEART}</li>
-     * <li>{@link Rating#RATING_PERCENTAGE}</li>
-     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
-     * </ul>
-     */
-    public void setRatingType(int type) {
-        try {
-            mBinder.setRatingType(type);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in setRatingType.", e);
-        }
-    }
-
-    /**
-     * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
-     * be made as to how a {@link MediaController} will handle these extras.
-     * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
-     *
-     * @param extras The extras associated with the {@link MediaSession}.
-     */
-    public void setExtras(@Nullable Bundle extras) {
-        try {
-            mBinder.setExtras(extras);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setExtras.", e);
-        }
-    }
-
-    /**
-     * Gets the controller information who sent the current request.
-     * <p>
-     * Note: This is only valid while in a request callback, such as
-     * {@link MediaSession.Callback#onPlay}.
-     *
-     * @throws IllegalStateException If this method is called outside of
-     * {@link MediaSession.Callback} methods.
-     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
-     */
-    public @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        if (mCallbackHandler == null || mCallbackHandler.mCurrentControllerInfo == null) {
-            throw new IllegalStateException(
-                    "This should be called inside of MediaSession.Callback methods");
-        }
-        return mCallbackHandler.mCurrentControllerInfo;
-    }
-
-    /**
-     * Returns the name of the package that sent the last media button, transport control, or
-     * command from controllers and the system. This is only valid while in a request callback, such
-     * as {@link MediaSession.Callback#onPlay}.
-     */
-    public String getCallingPackage() {
-        if (mCallbackHandler != null && mCallbackHandler.mCurrentControllerInfo != null) {
-            return mCallbackHandler.mCurrentControllerInfo.getPackageName();
-        }
-        return null;
-    }
-
-
-    /**
-     * Notify the system that the remote volume changed.
-     *
-     * @param provider The provider that is handling volume changes.
-     */
-    private void notifyRemoteVolumeChanged(VolumeProvider provider) {
-        synchronized (mLock) {
-            if (provider == null || provider != mVolumeProvider) {
-                Log.w(TAG, "Received update from stale volume provider");
-                return;
-            }
-        }
-        try {
-            mBinder.setCurrentVolume(provider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in notifyVolumeChanged", e);
-        }
-    }
-
-    void dispatchPrepare(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
-    }
-
-    void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
-    }
-
-    void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
-    }
-
-    void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
-    }
-
-    void dispatchPlay(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
-    }
-
-    void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
-    }
-
-    void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
-    }
-
-    void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
-    }
-
-    void dispatchSkipToItem(RemoteUserInfo caller, long id) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
-    }
-
-    void dispatchPause(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
-    }
-
-    void dispatchStop(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
-    }
-
-    void dispatchNext(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
-    }
-
-    void dispatchPrevious(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
-    }
-
-    void dispatchFastForward(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
-    }
-
-    void dispatchRewind(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
-    }
-
-    void dispatchSeekTo(RemoteUserInfo caller, long pos) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
-    }
-
-    void dispatchRate(RemoteUserInfo caller, Rating rating) {
-        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
-    }
-
-    void dispatchSetPlaybackSpeed(RemoteUserInfo caller, float speed) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SET_PLAYBACK_SPEED, speed, null);
-    }
-
-    void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
-        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
-    }
-
-    void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
-        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
-    }
-
-    void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
-            long delay) {
-        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
-                mediaButtonIntent, null, delay);
-    }
-
-    void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
-        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
-    }
-
-    void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
-    }
-
-    void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
-            ResultReceiver resultCb) {
-        Command cmd = new Command(command, args, resultCb);
-        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
-    }
-
-    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
-        postToCallbackDelayed(caller, what, obj, data, 0);
-    }
-
-    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
-            long delay) {
-        synchronized (mLock) {
-            if (mCallbackHandler != null) {
-                mCallbackHandler.post(caller, what, obj, data, delay);
-            }
-        }
-    }
-
-    /**
-     * Return true if this is considered an active playback state.
-     */
-    public static boolean isActiveState(int state) {
-        switch (state) {
-            case PlaybackState.STATE_FAST_FORWARDING:
-            case PlaybackState.STATE_REWINDING:
-            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
-            case PlaybackState.STATE_SKIPPING_TO_NEXT:
-            case PlaybackState.STATE_BUFFERING:
-            case PlaybackState.STATE_CONNECTING:
-            case PlaybackState.STATE_PLAYING:
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Interface for handling MediaButtoneEvent
-     */
-    public interface MediaButtonEventDelegate {
-        /**
-         * Called when a media button is pressed and this session has the
-         * highest priority or a controller sends a media button event to the
-         * session.
-         *
-         * @param mediaButtonIntent an intent containing the KeyEvent as an extra
-         * @return True if the event was handled, false otherwise.
-         */
-        boolean onMediaButtonIntent(Intent mediaButtonIntent);
-    }
-
-    /**
-     * Receives media buttons, transport controls, and commands from controllers
-     * and the system. A callback may be set using {@link #setCallback}.
-     * @hide
-     */
-    public static class CallbackWrapper implements MediaButtonEventDelegate {
-
-        private final MediaSession.Callback mCallback;
-
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-                MediaSessionEngine mSessionImpl;
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        CallbackMessageHandler mHandler;
-        private boolean mMediaPlayPauseKeyPending;
-
-        public CallbackWrapper(MediaSession.Callback callback) {
-            mCallback = callback;
-            if (mCallback != null) {
-                mCallback.onSetMediaButtonEventDelegate(this);
-            }
-        }
-
-        /**
-         * Called when a controller has sent a command to this session.
-         * The owner of the session may handle custom commands but is not
-         * required to.
-         *
-         * @param command The command name.
-         * @param args Optional parameters for the command, may be null.
-         * @param cb A result receiver to which a result may be sent by the command, may be null.
-         */
-        public void onCommand(@NonNull String command, @Nullable Bundle args,
-                @Nullable ResultReceiver cb) {
-            if (mCallback != null) {
-                mCallback.onCommand(command, args, cb);
-            }
-        }
-
-        /**
-         * Called when a media button is pressed and this session has the
-         * highest priority or a controller sends a media button event to the
-         * session. The default behavior will call the relevant method if the
-         * action for it was set.
-         * <p>
-         * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
-         * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
-         *
-         * @param mediaButtonIntent an intent containing the KeyEvent as an
-         *            extra
-         * @return True if the event was handled, false otherwise.
-         */
-        public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
-            return mCallback == null ? false : mCallback.onMediaButtonEvent(mediaButtonIntent);
-        }
-
-        private void handleMediaPlayPauseKeySingleTapIfPending() {
-            if (!mMediaPlayPauseKeyPending) {
-                return;
-            }
-            mMediaPlayPauseKeyPending = false;
-            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-            PlaybackState state = mSessionImpl.mPlaybackState;
-            long validActions = state == null ? 0 : state.getActions();
-            boolean isPlaying = state != null
-                    && state.getState() == PlaybackState.STATE_PLAYING;
-            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                    | PlaybackState.ACTION_PLAY)) != 0;
-            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                    | PlaybackState.ACTION_PAUSE)) != 0;
-            if (isPlaying && canPause) {
-                onPause();
-            } else if (!isPlaying && canPlay) {
-                onPlay();
-            }
-        }
-
-        /**
-         * Override to handle requests to prepare playback. During the preparation, a session should
-         * not hold audio focus in order to allow other sessions play seamlessly. The state of
-         * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
-         * done.
-         */
-        public void onPrepare() {
-            if (mCallback != null) {
-                mCallback.onPrepare();
-            }
-        }
-
-        /**
-         * Override to handle requests to prepare for playing a specific mediaId that was provided
-         * by your app's {@link MediaBrowserService}. During the preparation, a session should not
-         * hold audio focus in order to allow other sessions play seamlessly. The state of playback
-         * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
-         * The playback of the prepared content should start in the implementation of
-         * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
-         * playback without preparation.
-         */
-        public void onPrepareFromMediaId(String mediaId, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPrepareFromMediaId(mediaId, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to prepare playback from a search query. An empty query
-         * indicates that the app may prepare any music. The implementation should attempt to make a
-         * smart choice about what to play. During the preparation, a session should not hold audio
-         * focus in order to allow other sessions play seamlessly. The state of playback should be
-         * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
-         * of the prepared content should start in the implementation of {@link #onPlay}. Override
-         * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
-         */
-        public void onPrepareFromSearch(String query, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPrepareFromSearch(query, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to prepare a specific media item represented by a URI.
-         * During the preparation, a session should not hold audio focus in order to allow
-         * other sessions play seamlessly. The state of playback should be updated to
-         * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
-         * The playback of the prepared content should start in the implementation of
-         * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
-         * for starting playback without preparation.
-         */
-        public void onPrepareFromUri(Uri uri, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPrepareFromUri(uri, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to begin playback.
-         */
-        public void onPlay() {
-            if (mCallback != null) {
-                mCallback.onPlay();
-            }
-        }
-
-        /**
-         * Override to handle requests to begin playback from a search query. An
-         * empty query indicates that the app may play any music. The
-         * implementation should attempt to make a smart choice about what to
-         * play.
-         */
-        public void onPlayFromSearch(String query, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPlayFromSearch(query, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to play a specific mediaId that was
-         * provided by your app's {@link MediaBrowserService}.
-         */
-        public void onPlayFromMediaId(String mediaId, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPlayFromMediaId(mediaId, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to play a specific media item represented by a URI.
-         */
-        public void onPlayFromUri(Uri uri, Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onPlayFromUri(uri, extras);
-            }
-        }
-
-        /**
-         * Override to handle requests to play an item with a given id from the
-         * play queue.
-         */
-        public void onSkipToQueueItem(long id) {
-            if (mCallback != null) {
-                mCallback.onSkipToQueueItem(id);
-            }
-        }
-
-        /**
-         * Override to handle requests to pause playback.
-         */
-        public void onPause() {
-            if (mCallback != null) {
-                mCallback.onPause();
-            }
-        }
-
-        /**
-         * Override to handle requests to skip to the next media item.
-         */
-        public void onSkipToNext() {
-            if (mCallback != null) {
-                mCallback.onSkipToNext();
-            }
-        }
-
-        /**
-         * Override to handle requests to skip to the previous media item.
-         */
-        public void onSkipToPrevious() {
-            if (mCallback != null) {
-                mCallback.onSkipToPrevious();
-            }
-        }
-
-        /**
-         * Override to handle requests to fast forward.
-         */
-        public void onFastForward() {
-            if (mCallback != null) {
-                mCallback.onFastForward();
-            }
-        }
-
-        /**
-         * Override to handle requests to rewind.
-         */
-        public void onRewind() {
-            if (mCallback != null) {
-                mCallback.onRewind();
-            }
-        }
-
-        /**
-         * Override to handle requests to stop playback.
-         */
-        public void onStop() {
-            if (mCallback != null) {
-                mCallback.onStop();
-            }
-        }
-
-        /**
-         * Override to handle requests to seek to a specific position in ms.
-         *
-         * @param pos New position to move to, in milliseconds.
-         */
-        public void onSeekTo(long pos) {
-            if (mCallback != null) {
-                mCallback.onSeekTo(pos);
-            }
-        }
-
-        /**
-         * Override to handle the item being rated.
-         *
-         * @param rating
-         */
-        public void onSetRating(@NonNull Rating rating) {
-            if (mCallback != null) {
-                mCallback.onSetRating(rating);
-            }
-        }
-
-        /**
-         * Override to handle the playback speed change.
-         *
-         * @param speed the playback speed
-         */
-        public void onSetPlaybackSpeed(float speed) {
-            if (mCallback != null) {
-                mCallback.onSetPlaybackSpeed(speed);
-            }
-        }
-
-        /**
-         * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
-         * performed.
-         *
-         * @param action The action that was originally sent in the
-         *               {@link PlaybackState.CustomAction}.
-         * @param extras Optional extras specified by the {@link MediaController}.
-         */
-        public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
-            if (mCallback != null) {
-                mCallback.onCustomAction(action, extras);
-            }
-        }
-
-        @Override
-        public boolean onMediaButtonIntent(Intent mediaButtonIntent) {
-            if (mSessionImpl != null && mHandler != null
-                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
-                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
-                    PlaybackState state = mSessionImpl.mPlaybackState;
-                    long validActions = state == null ? 0 : state.getActions();
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                        case KeyEvent.KEYCODE_HEADSETHOOK:
-                            if (ke.getRepeatCount() > 0) {
-                                // Consider long-press as a single tap.
-                                handleMediaPlayPauseKeySingleTapIfPending();
-                            } else if (mMediaPlayPauseKeyPending) {
-                                // Consider double tap as the next.
-                                mHandler.removeMessages(CallbackMessageHandler
-                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-                                mMediaPlayPauseKeyPending = false;
-                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                    onSkipToNext();
-                                }
-                            } else {
-                                mMediaPlayPauseKeyPending = true;
-                                mSessionImpl.dispatchMediaButtonDelayed(
-                                        mSessionImpl.getCurrentControllerInfo(),
-                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
-                            }
-                            return true;
-                        default:
-                            // If another key is pressed within double tap timeout, consider the
-                            // pending play/pause as a single tap to handle media keys in order.
-                            handleMediaPlayPauseKeySingleTapIfPending();
-                            break;
-                    }
-
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY:
-                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
-                                onPlay();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
-                                onPause();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_NEXT:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                onSkipToNext();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
-                                onSkipToPrevious();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_STOP:
-                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
-                                onStop();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
-                                onFastForward();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_REWIND:
-                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
-                                onRewind();
-                                return true;
-                            }
-                            break;
-                    }
-                }
-            }
-            return false;
-        }
-    }
-
-     /**
-     * A single item that is part of the play queue. It contains a description
-     * of the item and its id in the queue.
-     */
-    public static final class QueueItem {
-        /**
-         * This id is reserved. No items can be explicitly assigned this id.
-         */
-        public static final int UNKNOWN_ID = -1;
-
-        private final MediaDescription mDescription;
-        private final long mId;
-
-        /**
-         * Create a new {@link MediaSession.QueueItem}.
-         *
-         * @param description The {@link MediaDescription} for this item.
-         * @param id An identifier for this item. It must be unique within the
-         *            play queue and cannot be {@link #UNKNOWN_ID}.
-         */
-        public QueueItem(MediaDescription description, long id) {
-            if (description == null) {
-                throw new IllegalArgumentException("Description cannot be null.");
-            }
-            if (id == UNKNOWN_ID) {
-                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
-            }
-            mDescription = description;
-            mId = id;
-        }
-
-        public QueueItem(Parcel in) {
-            mDescription = MediaDescription.CREATOR.createFromParcel(in);
-            mId = in.readLong();
-        }
-
-        /**
-         * Get the description for this item.
-         */
-        public MediaDescription getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Get the queue id for this item.
-         */
-        public long getQueueId() {
-            return mId;
-        }
-
-        /**
-         * Flatten this object in to a Parcel.
-         *
-         * @param dest The Parcel in which the object should be written.
-         * @param flags Additional flags about how the object should be written.
-         */
-        public void writeToParcel(Parcel dest, int flags) {
-            mDescription.writeToParcel(dest, flags);
-            dest.writeLong(mId);
-        }
-
-        @Override
-        public String toString() {
-            return "MediaSession.QueueItem {" + "Description=" + mDescription + ", Id=" + mId
-                    + " }";
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o == null) {
-                return false;
-            }
-
-            if (!(o instanceof QueueItem)) {
-                return false;
-            }
-
-            final QueueItem item = (QueueItem) o;
-            if (mId != item.mId) {
-                return false;
-            }
-
-            if (!Objects.equals(mDescription, item.mDescription)) {
-                return false;
-            }
-
-            return true;
-        }
-    }
-
-    private static final class Command {
-        public final String command;
-        public final Bundle extras;
-        public final ResultReceiver stub;
-
-        Command(String command, Bundle extras, ResultReceiver stub) {
-            this.command = command;
-            this.extras = extras;
-            this.stub = stub;
-        }
-    }
-
-    private class CallbackMessageHandler extends Handler {
-        private static final int MSG_COMMAND = 1;
-        private static final int MSG_MEDIA_BUTTON = 2;
-        private static final int MSG_PREPARE = 3;
-        private static final int MSG_PREPARE_MEDIA_ID = 4;
-        private static final int MSG_PREPARE_SEARCH = 5;
-        private static final int MSG_PREPARE_URI = 6;
-        private static final int MSG_PLAY = 7;
-        private static final int MSG_PLAY_MEDIA_ID = 8;
-        private static final int MSG_PLAY_SEARCH = 9;
-        private static final int MSG_PLAY_URI = 10;
-        private static final int MSG_SKIP_TO_ITEM = 11;
-        private static final int MSG_PAUSE = 12;
-        private static final int MSG_STOP = 13;
-        private static final int MSG_NEXT = 14;
-        private static final int MSG_PREVIOUS = 15;
-        private static final int MSG_FAST_FORWARD = 16;
-        private static final int MSG_REWIND = 17;
-        private static final int MSG_SEEK_TO = 18;
-        private static final int MSG_RATE = 19;
-        private static final int MSG_SET_PLAYBACK_SPEED = 20;
-        private static final int MSG_CUSTOM_ACTION = 21;
-        private static final int MSG_ADJUST_VOLUME = 22;
-        private static final int MSG_SET_VOLUME = 23;
-        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 24;
-
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        CallbackWrapper mCallbackWrapper;
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        RemoteUserInfo mCurrentControllerInfo;
-
-        CallbackMessageHandler(Looper looper, CallbackWrapper callbackWrapper) {
-            super(looper);
-            mCallbackWrapper = callbackWrapper;
-            mCallbackWrapper.mHandler = this;
-        }
-
-        void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
-            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
-            Message msg = obtainMessage(what, objWithCaller);
-            msg.setAsynchronous(true);
-            msg.setData(data);
-            if (delayMs > 0) {
-                sendMessageDelayed(msg, delayMs);
-            } else {
-                sendMessage(msg);
-            }
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
-
-            VolumeProvider vp;
-            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
-
-            switch (msg.what) {
-                case MSG_COMMAND:
-                    Command cmd = (Command) obj;
-                    mCallbackWrapper.onCommand(cmd.command, cmd.extras, cmd.stub);
-                    break;
-                case MSG_MEDIA_BUTTON:
-                    mCallbackWrapper.onMediaButtonEvent((Intent) obj);
-                    break;
-                case MSG_PREPARE:
-                    mCallbackWrapper.onPrepare();
-                    break;
-                case MSG_PREPARE_MEDIA_ID:
-                    mCallbackWrapper.onPrepareFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_SEARCH:
-                    mCallbackWrapper.onPrepareFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_URI:
-                    mCallbackWrapper.onPrepareFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_PLAY:
-                    mCallbackWrapper.onPlay();
-                    break;
-                case MSG_PLAY_MEDIA_ID:
-                    mCallbackWrapper.onPlayFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_SEARCH:
-                    mCallbackWrapper.onPlayFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_URI:
-                    mCallbackWrapper.onPlayFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_SKIP_TO_ITEM:
-                    mCallbackWrapper.onSkipToQueueItem((Long) obj);
-                    break;
-                case MSG_PAUSE:
-                    mCallbackWrapper.onPause();
-                    break;
-                case MSG_STOP:
-                    mCallbackWrapper.onStop();
-                    break;
-                case MSG_NEXT:
-                    mCallbackWrapper.onSkipToNext();
-                    break;
-                case MSG_PREVIOUS:
-                    mCallbackWrapper.onSkipToPrevious();
-                    break;
-                case MSG_FAST_FORWARD:
-                    mCallbackWrapper.onFastForward();
-                    break;
-                case MSG_REWIND:
-                    mCallbackWrapper.onRewind();
-                    break;
-                case MSG_SEEK_TO:
-                    mCallbackWrapper.onSeekTo((Long) obj);
-                    break;
-                case MSG_RATE:
-                    mCallbackWrapper.onSetRating((Rating) obj);
-                    break;
-                case MSG_SET_PLAYBACK_SPEED:
-                    mCallbackWrapper.onSetPlaybackSpeed((Float) obj);
-                    break;
-                case MSG_CUSTOM_ACTION:
-                    mCallbackWrapper.onCustomAction((String) obj, msg.getData());
-                    break;
-                case MSG_ADJUST_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onAdjustVolume((int) obj);
-                    }
-                    break;
-                case MSG_SET_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onSetVolumeTo((int) obj);
-                    }
-                    break;
-                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
-                    mCallbackWrapper.handleMediaPlayPauseKeySingleTapIfPending();
-                    break;
-            }
-            mCurrentControllerInfo = null;
-        }
-    }
-}
diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
index 6ffdc2b..c858a60 100644
--- a/media/java/android/media/session/SessionCallbackLink.java
+++ b/media/java/android/media/session/SessionCallbackLink.java
@@ -49,9 +49,9 @@
      * Constructor for stub (Callee)
      * @hide
      */
-    public SessionCallbackLink(@NonNull Context context) {
+    public SessionCallbackLink(@NonNull Context context, MediaSession session) {
         mContext = context;
-        mISessionCallback = new CallbackStub();
+        mISessionCallback = new CallbackStub(session);
     }
 
     /**
@@ -63,15 +63,6 @@
     }
 
     /**
-     * Set {@link MediaSessionEngine} which will be used by {@link CallbackStub}.
-     */
-    void setSessionEngine(@Nullable MediaSessionEngine sessionImpl) {
-        if (mISessionCallback instanceof CallbackStub) {
-            ((CallbackStub) mISessionCallback).mSessionImpl = new WeakReference<>(sessionImpl);
-        }
-    }
-
-    /**
      * Notify session that a controller sends a command.
      *
      * @param packageName the package name of the controller
@@ -568,7 +559,11 @@
             };
 
     private class CallbackStub extends ISessionCallback.Stub {
-        private WeakReference<MediaSessionEngine> mSessionImpl;
+        private WeakReference<MediaSession> mMediaSession;
+
+        private CallbackStub(MediaSession session) {
+            mMediaSession = new WeakReference<>(session);
+        }
 
         private RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) {
             return new RemoteUserInfo(packageName, pid, uid);
@@ -580,9 +575,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid),
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid),
                             command, args, cb);
                 }
             } finally {
@@ -596,9 +591,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchMediaButton(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchMediaButton(
                             createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent);
                 }
             } finally {
@@ -615,9 +610,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid),
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid),
                             mediaButtonIntent);
                 }
             } finally {
@@ -631,9 +626,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -646,9 +641,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPrepareFromMediaId(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPrepareFromMediaId(
                             createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
                 }
             } finally {
@@ -662,9 +657,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPrepareFromSearch(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPrepareFromSearch(
                             createRemoteUserInfo(packageName, pid, uid), query, extras);
                 }
             } finally {
@@ -678,9 +673,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPrepareFromUri(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPrepareFromUri(
                             createRemoteUserInfo(packageName, pid, uid), uri, extras);
                 }
             } finally {
@@ -694,9 +689,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -709,9 +704,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPlayFromMediaId(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPlayFromMediaId(
                             createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
                 }
             } finally {
@@ -725,9 +720,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPlayFromSearch(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPlayFromSearch(
                             createRemoteUserInfo(packageName, pid, uid), query, extras);
                 }
             } finally {
@@ -741,9 +736,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPlayFromUri(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPlayFromUri(
                             createRemoteUserInfo(packageName, pid, uid), uri, extras);
                 }
             } finally {
@@ -757,9 +752,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchSkipToItem(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchSkipToItem(
                             createRemoteUserInfo(packageName, pid, uid), id);
                 }
             } finally {
@@ -773,9 +768,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPause(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -788,9 +783,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchStop(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -803,9 +798,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchNext(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -818,9 +813,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -833,9 +828,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchFastForward(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchFastForward(
                             createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
@@ -849,9 +844,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid));
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -864,9 +859,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchSeekTo(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchSeekTo(
                             createRemoteUserInfo(packageName, pid, uid), pos);
                 }
             } finally {
@@ -880,9 +875,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchRate(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchRate(
                             createRemoteUserInfo(packageName, pid, uid), rating);
                 }
             } finally {
@@ -896,9 +891,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchSetPlaybackSpeed(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchSetPlaybackSpeed(
                             createRemoteUserInfo(packageName, pid, uid), speed);
                 }
             } finally {
@@ -912,9 +907,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchCustomAction(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchCustomAction(
                             createRemoteUserInfo(packageName, pid, uid), action, args);
                 }
             } finally {
@@ -928,9 +923,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchAdjustVolume(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchAdjustVolume(
                             createRemoteUserInfo(packageName, pid, uid), direction);
                 }
             } finally {
@@ -944,9 +939,9 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionEngine sessionImpl = mSessionImpl.get();
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchSetVolumeTo(
+                MediaSession session = mMediaSession.get();
+                if (session != null) {
+                    session.dispatchSetVolumeTo(
                             createRemoteUserInfo(packageName, pid, uid), value);
                 }
             } finally {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d7ab854..f412161 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -149,6 +149,7 @@
 };
 
 struct SessionExceptionErrorCodes {
+    jint kErrorUnknown;
     jint kResourceContention;
 } gSessionExceptionErrorCodes;
 
@@ -888,6 +889,8 @@
     gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
     GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
 
+    GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
+    gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
     gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
 }
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 3ec0903..24fff06 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -760,9 +760,9 @@
     return jStatus;
 }
 
-static jint android_media_MediaRecord_setMicrophoneDirection(
+static jint android_media_MediaRecord_setPreferredMicrophoneDirection(
         JNIEnv *env, jobject thiz, jint direction) {
-    ALOGV("setMicrophoneDirection(%d)", direction);
+    ALOGV("setPreferredMicrophoneDirection(%d)", direction);
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     if (mr == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -771,7 +771,7 @@
 
     jint jStatus = AUDIO_JAVA_SUCCESS;
     status_t status =
-        mr->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+        mr->setPreferredMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
     if (status != NO_ERROR) {
         jStatus = nativeToJavaStatus(status);
     }
@@ -779,9 +779,9 @@
     return jStatus;
 }
 
-static jint  android_media_MediaRecord_setMicrophoneFieldDimension(
+static jint  android_media_MediaRecord_setPreferredMicrophoneFieldDimension(
         JNIEnv *env, jobject thiz, jfloat zoom) {
-    ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+    ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     if (mr == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -789,7 +789,7 @@
     }
 
     jint jStatus = AUDIO_JAVA_SUCCESS;
-    status_t status = mr->setMicrophoneFieldDimension(zoom);
+    status_t status = mr->setPreferredMicrophoneFieldDimension(zoom);
     if (status != NO_ERROR) {
         jStatus = nativeToJavaStatus(status);
     }
@@ -850,8 +850,10 @@
 
     {"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
     {"native_getPortId", "()I", (void *)android_media_MediaRecord_getPortId},
-    {"native_setMicrophoneDirection", "(I)I", (void *)android_media_MediaRecord_setMicrophoneDirection},
-    {"native_setMicrophoneFieldDimension", "(F)I", (void *)android_media_MediaRecord_setMicrophoneFieldDimension},
+    {"native_setPreferredMicrophoneDirection", "(I)I",
+            (void *)android_media_MediaRecord_setPreferredMicrophoneDirection},
+    {"native_setPreferredMicrophoneFieldDimension", "(F)I",
+            (void *)android_media_MediaRecord_setPreferredMicrophoneFieldDimension},
 };
 
 // This function only registers the native methods, and is called from
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index e1dc406..1f2480b 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -148,6 +148,7 @@
     AHardwareBuffer_getNativeHandle; # introduced=26
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock; # introduced=26
+    AHardwareBuffer_lockAndGetInfo; # introduced=29
     AHardwareBuffer_lockPlanes; # introduced=29
     AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
     AHardwareBuffer_release; # introduced=26
diff --git a/packages/DynamicAndroidInstallationService/Android.mk b/packages/DynamicSystemInstallationService/Android.mk
similarity index 86%
rename from packages/DynamicAndroidInstallationService/Android.mk
rename to packages/DynamicSystemInstallationService/Android.mk
index 13d96ac..16aca1b 100644
--- a/packages/DynamicAndroidInstallationService/Android.mk
+++ b/packages/DynamicSystemInstallationService/Android.mk
@@ -8,7 +8,7 @@
 
 LOCAL_USE_AAPT2 := true
 
-LOCAL_PACKAGE_NAME := DynamicAndroidInstallationService
+LOCAL_PACKAGE_NAME := DynamicSystemInstallationService
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/packages/DynamicAndroidInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml
similarity index 80%
rename from packages/DynamicAndroidInstallationService/AndroidManifest.xml
rename to packages/DynamicSystemInstallationService/AndroidManifest.xml
index 32acad4..2911117 100644
--- a/packages/DynamicAndroidInstallationService/AndroidManifest.xml
+++ b/packages/DynamicSystemInstallationService/AndroidManifest.xml
@@ -1,10 +1,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.dynandroid"
+        package="com.android.dynsystem"
         android:sharedUserId="android.uid.system">
 
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.MANAGE_DYNAMIC_ANDROID" />
+    <uses-permission android:name="android.permission.MANAGE_DYNAMIC_SYSTEM" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
@@ -13,24 +13,24 @@
         android:label="@string/app_name">
 
         <service
-            android:name=".DynamicAndroidInstallationService"
+            android:name=".DynamicSystemInstallationService"
             android:enabled="true"
             android:exported="true"
-            android:permission="android.permission.MANAGE_DYNAMIC_ANDROID"
-            android:process=":dynandroid">
+            android:permission="android.permission.MANAGE_DYNAMIC_SYSTEM"
+            android:process=":dynsystem">
             <intent-filter>
-                <action android:name="android.content.action.NOTIFY_IF_IN_USE" />
+                <action android:name="android.os.image.action.NOTIFY_IF_IN_USE" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </service>
 
         <activity android:name=".VerificationActivity"
             android:exported="true"
-            android:permission="android.permission.MANAGE_DYNAMIC_ANDROID"
+            android:permission="android.permission.MANAGE_DYNAMIC_SYSTEM"
             android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
-            android:process=":dynandroid">
+            android:process=":dynsystem">
             <intent-filter>
-                <action android:name="android.content.action.START_INSTALL" />
+                <action android:name="android.os.image.action.START_INSTALL" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
diff --git a/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2 b/packages/DynamicSystemInstallationService/MODULE_LICENSE_APACHE2
similarity index 100%
rename from packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2
rename to packages/DynamicSystemInstallationService/MODULE_LICENSE_APACHE2
diff --git a/packages/DynamicAndroidInstallationService/NOTICE b/packages/DynamicSystemInstallationService/NOTICE
similarity index 100%
rename from packages/DynamicAndroidInstallationService/NOTICE
rename to packages/DynamicSystemInstallationService/NOTICE
diff --git a/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml b/packages/DynamicSystemInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
similarity index 100%
rename from packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
rename to packages/DynamicSystemInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
similarity index 64%
rename from packages/DynamicAndroidInstallationService/res/values/strings.xml
rename to packages/DynamicSystemInstallationService/res/values/strings.xml
index 03c7c28..a72e4e2 100644
--- a/packages/DynamicAndroidInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -12,14 +12,14 @@
     <!-- password page description [CHAR LIMIT=128] -->
     <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
 
-    <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] -->
+    <!-- Displayed on notification: AndroidOnTap installation is completed [CHAR LIMIT=128] -->
     <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string>
-    <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+    <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
     <string name="notification_install_inprogress">Installation is in progress.</string>
-    <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+    <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
     <string name="notification_install_failed">Installation Failed.</string>
     <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] -->
-    <string name="notification_dynandroid_in_use">We are running in AndroidOnTap.</string>
+    <string name="notification_dynsystem_in_use">We are running in AndroidOnTap.</string>
 
     <!-- Action on notification: Cancel installation [CHAR LIMIT=16] -->
     <string name="notification_action_cancel">Cancel</string>
@@ -28,11 +28,11 @@
     <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_uninstall">Uninstall</string>
     <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
-    <string name="notification_action_reboot_to_dynandroid">Reboot</string>
+    <string name="notification_action_reboot_to_dynsystem">Reboot</string>
 
-    <!-- Toast when installed DynamicAndroid is discarded [CHAR LIMIT=64] -->
-    <string name="toast_dynandroid_discarded">Installed AndroidOnTap is discarded.</string>
-    <!-- Toast when we fail to launch into DynamicAndroid [CHAR LIMIT=64] -->
-    <string name="toast_failed_to_reboot_to_dynandroid">Failed to reboot into AndroidOnTap.</string>
+    <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] -->
+    <string name="toast_dynsystem_discarded">Installed AndroidOnTap is discarded.</string>
+    <!-- Toast when we fail to launch into AndroidOnTap [CHAR LIMIT=64] -->
+    <string name="toast_failed_to_reboot_to_dynsystem">Failed to reboot into AndroidOnTap.</string>
 
 </resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
similarity index 84%
rename from packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
index dd1be89..38576ee 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
@@ -14,20 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.dynandroid;
+package com.android.dynsystem;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.DynamicAndroidClient;
 import android.content.Intent;
 import android.os.UserHandle;
+import android.os.image.DynamicSystemClient;
 import android.util.Log;
 
 
 /**
  * A BoardcastReceiver waiting for ACTION_BOOT_COMPLETED and ask
  * the service to display a notification if we are currently running
- * in DynamicAndroid.
+ * in DynamicSystem.
  */
 public class BootCompletedReceiver extends BroadcastReceiver {
 
@@ -41,9 +41,9 @@
 
         if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
             Intent startServiceIntent = new Intent(
-                    context, DynamicAndroidInstallationService.class);
+                    context, DynamicSystemInstallationService.class);
 
-            startServiceIntent.setAction(DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE);
+            startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
             context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
         }
     }
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
similarity index 78%
rename from packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
index d942bab..df2c571 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
@@ -14,28 +14,28 @@
  * limitations under the License.
  */
 
-package com.android.dynandroid;
+package com.android.dynsystem;
 
-import static android.content.DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE;
-import static android.content.DynamicAndroidClient.ACTION_START_INSTALL;
-import static android.content.DynamicAndroidClient.CAUSE_ERROR_EXCEPTION;
-import static android.content.DynamicAndroidClient.CAUSE_ERROR_INVALID_URL;
-import static android.content.DynamicAndroidClient.CAUSE_ERROR_IO;
-import static android.content.DynamicAndroidClient.CAUSE_INSTALL_CANCELLED;
-import static android.content.DynamicAndroidClient.CAUSE_INSTALL_COMPLETED;
-import static android.content.DynamicAndroidClient.CAUSE_NOT_SPECIFIED;
-import static android.content.DynamicAndroidClient.STATUS_IN_PROGRESS;
-import static android.content.DynamicAndroidClient.STATUS_IN_USE;
-import static android.content.DynamicAndroidClient.STATUS_NOT_STARTED;
-import static android.content.DynamicAndroidClient.STATUS_READY;
 import static android.os.AsyncTask.Status.FINISHED;
 import static android.os.AsyncTask.Status.PENDING;
 import static android.os.AsyncTask.Status.RUNNING;
+import static android.os.image.DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE;
+import static android.os.image.DynamicSystemClient.ACTION_START_INSTALL;
+import static android.os.image.DynamicSystemClient.CAUSE_ERROR_EXCEPTION;
+import static android.os.image.DynamicSystemClient.CAUSE_ERROR_INVALID_URL;
+import static android.os.image.DynamicSystemClient.CAUSE_ERROR_IO;
+import static android.os.image.DynamicSystemClient.CAUSE_INSTALL_CANCELLED;
+import static android.os.image.DynamicSystemClient.CAUSE_INSTALL_COMPLETED;
+import static android.os.image.DynamicSystemClient.CAUSE_NOT_SPECIFIED;
+import static android.os.image.DynamicSystemClient.STATUS_IN_PROGRESS;
+import static android.os.image.DynamicSystemClient.STATUS_IN_USE;
+import static android.os.image.DynamicSystemClient.STATUS_NOT_STARTED;
+import static android.os.image.DynamicSystemClient.STATUS_READY;
 
-import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
-import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
-import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_IO;
-import static com.android.dynandroid.InstallationAsyncTask.RESULT_OK;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_IO;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_OK;
 
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -43,16 +43,16 @@
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
-import android.content.DynamicAndroidClient;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.DynamicAndroidManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.image.DynamicSystemClient;
+import android.os.image.DynamicSystemManager;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -60,31 +60,31 @@
 import java.util.ArrayList;
 
 /**
- * This class is the service in charge of DynamicAndroid installation.
+ * This class is the service in charge of DynamicSystem installation.
  * It also posts status to notification bar and wait for user's
  * cancel and confirm commnands.
  */
-public class DynamicAndroidInstallationService extends Service
+public class DynamicSystemInstallationService extends Service
         implements InstallationAsyncTask.InstallStatusListener {
 
-    private static final String TAG = "DynAndroidInstallationService";
+    private static final String TAG = "DynSystemInstallationService";
 
     /*
      * Intent actions
      */
     private static final String ACTION_CANCEL_INSTALL =
-            "com.android.dynandroid.ACTION_CANCEL_INSTALL";
+            "com.android.dynsystem.ACTION_CANCEL_INSTALL";
     private static final String ACTION_DISCARD_INSTALL =
-            "com.android.dynandroid.ACTION_DISCARD_INSTALL";
-    private static final String ACTION_REBOOT_TO_DYN_ANDROID =
-            "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID";
+            "com.android.dynsystem.ACTION_DISCARD_INSTALL";
+    private static final String ACTION_REBOOT_TO_DYN_SYSTEM =
+            "com.android.dynsystem.ACTION_REBOOT_TO_DYN_SYSTEM";
     private static final String ACTION_REBOOT_TO_NORMAL =
-            "com.android.dynandroid.ACTION_REBOOT_TO_NORMAL";
+            "com.android.dynsystem.ACTION_REBOOT_TO_NORMAL";
 
     /*
      * For notification
      */
-    private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynandroid";
+    private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynsystem";
     private static final int NOTIFICATION_ID = 1;
 
     /*
@@ -97,15 +97,15 @@
     final Messenger mMessenger = new Messenger(new IncomingHandler(this));
 
     static class IncomingHandler extends Handler {
-        private final WeakReference<DynamicAndroidInstallationService> mWeakService;
+        private final WeakReference<DynamicSystemInstallationService> mWeakService;
 
-        IncomingHandler(DynamicAndroidInstallationService service) {
+        IncomingHandler(DynamicSystemInstallationService service) {
             mWeakService = new WeakReference<>(service);
         }
 
         @Override
         public void handleMessage(Message msg) {
-            DynamicAndroidInstallationService service = mWeakService.get();
+            DynamicSystemInstallationService service = mWeakService.get();
 
             if (service != null) {
                 service.handleMessage(msg);
@@ -113,7 +113,7 @@
         }
     }
 
-    private DynamicAndroidManager mDynAndroid;
+    private DynamicSystemManager mDynSystem;
     private NotificationManager mNM;
 
     private long mSystemSize;
@@ -130,7 +130,7 @@
 
         prepareNotification();
 
-        mDynAndroid = (DynamicAndroidManager) getSystemService(Context.DYNAMIC_ANDROID_SERVICE);
+        mDynSystem = (DynamicSystemManager) getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
     }
 
     @Override
@@ -156,8 +156,8 @@
             executeCancelCommand();
         } else if (ACTION_DISCARD_INSTALL.equals(action)) {
             executeDiscardCommand();
-        } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) {
-            executeRebootToDynAndroidCommand();
+        } else if (ACTION_REBOOT_TO_DYN_SYSTEM.equals(action)) {
+            executeRebootToDynSystemCommand();
         } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) {
             executeRebootToNormalCommand();
         } else if (ACTION_NOTIFY_IF_IN_USE.equals(action)) {
@@ -215,17 +215,17 @@
             return;
         }
 
-        if (isInDynamicAndroid()) {
-            Log.e(TAG, "We are already running in DynamicAndroid");
+        if (isInDynamicSystem()) {
+            Log.e(TAG, "We are already running in DynamicSystem");
             return;
         }
 
-        String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
-        mSystemSize = intent.getLongExtra(DynamicAndroidClient.KEY_SYSTEM_SIZE, 0);
-        mUserdataSize = intent.getLongExtra(DynamicAndroidClient.KEY_USERDATA_SIZE, 0);
+        String url = intent.getStringExtra(DynamicSystemClient.KEY_SYSTEM_URL);
+        mSystemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
+        mUserdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
 
         mInstallTask = new InstallationAsyncTask(
-                url, mSystemSize, mUserdataSize, mDynAndroid, this);
+                url, mSystemSize, mUserdataSize, mDynSystem, this);
 
         mInstallTask.execute();
 
@@ -251,7 +251,7 @@
     }
 
     private void executeDiscardCommand() {
-        if (isInDynamicAndroid()) {
+        if (isInDynamicSystem()) {
             Log.e(TAG, "We are now running in AOT, please reboot to normal system first");
             return;
         }
@@ -262,16 +262,16 @@
         }
 
         Toast.makeText(this,
-                getString(R.string.toast_dynandroid_discarded),
+                getString(R.string.toast_dynsystem_discarded),
                 Toast.LENGTH_LONG).show();
 
         resetTaskAndStop();
         postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
 
-        mDynAndroid.remove();
+        mDynSystem.remove();
     }
 
-    private void executeRebootToDynAndroidCommand() {
+    private void executeRebootToDynSystemCommand() {
         if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) {
             Log.e(TAG, "Trying to reboot to AOT while there is no complete installation");
             return;
@@ -282,10 +282,10 @@
             mNM.cancel(NOTIFICATION_ID);
 
             Toast.makeText(this,
-                    getString(R.string.toast_failed_to_reboot_to_dynandroid),
+                    getString(R.string.toast_failed_to_reboot_to_dynsystem),
                     Toast.LENGTH_LONG).show();
 
-            mDynAndroid.remove();
+            mDynSystem.remove();
 
             return;
         }
@@ -293,12 +293,12 @@
         PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
 
         if (powerManager != null) {
-            powerManager.reboot("dynandroid");
+            powerManager.reboot("dynsystem");
         }
     }
 
     private void executeRebootToNormalCommand() {
-        if (!isInDynamicAndroid()) {
+        if (!isInDynamicSystem()) {
             Log.e(TAG, "It's already running in normal system.");
             return;
         }
@@ -346,7 +346,7 @@
     }
 
     private PendingIntent createPendingIntent(String action) {
-        Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
+        Intent intent = new Intent(this, DynamicSystemInstallationService.class);
         intent.setAction(action);
         return PendingIntent.getService(this, 0, intent, 0);
     }
@@ -375,8 +375,8 @@
                 builder.setContentText(getString(R.string.notification_install_completed));
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_reboot_to_dynandroid),
-                        createPendingIntent(ACTION_REBOOT_TO_DYN_ANDROID)).build());
+                        null, getString(R.string.notification_action_reboot_to_dynsystem),
+                        createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build());
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_discard),
@@ -385,7 +385,7 @@
                 break;
 
             case STATUS_IN_USE:
-                builder.setContentText(getString(R.string.notification_dynandroid_in_use));
+                builder.setContentText(getString(R.string.notification_dynsystem_in_use));
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_uninstall),
@@ -409,7 +409,7 @@
     }
 
     private boolean verifyRequest(Intent intent) {
-        String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
+        String url = intent.getStringExtra(DynamicSystemClient.KEY_SYSTEM_URL);
 
         return VerificationActivity.isVerified(url);
     }
@@ -443,16 +443,16 @@
     private void notifyOneClient(Messenger client, int status, int cause) throws RemoteException {
         Bundle bundle = new Bundle();
 
-        bundle.putLong(DynamicAndroidClient.KEY_INSTALLED_SIZE, mInstalledSize);
+        bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mInstalledSize);
 
         client.send(Message.obtain(null,
-                  DynamicAndroidClient.MSG_POST_STATUS, status, cause, bundle));
+                  DynamicSystemClient.MSG_POST_STATUS, status, cause, bundle));
     }
 
     private int getStatus() {
-        if (isInDynamicAndroid()) {
+        if (isInDynamicSystem()) {
             return STATUS_IN_USE;
-        } else if (isDynamicAndroidInstalled()) {
+        } else if (isDynamicSystemInstalled()) {
             return STATUS_READY;
         } else if (mInstallTask == null) {
             return STATUS_NOT_STARTED;
@@ -479,17 +479,17 @@
         }
     }
 
-    private boolean isInDynamicAndroid() {
-        return mDynAndroid.isInUse();
+    private boolean isInDynamicSystem() {
+        return mDynSystem.isInUse();
     }
 
-    private boolean isDynamicAndroidInstalled() {
-        return mDynAndroid.isInstalled();
+    private boolean isDynamicSystemInstalled() {
+        return mDynSystem.isInstalled();
     }
 
     void handleMessage(Message msg) {
         switch (msg.what) {
-            case DynamicAndroidClient.MSG_REGISTER_LISTENER:
+            case DynamicSystemClient.MSG_REGISTER_LISTENER:
                 try {
                     Messenger client = msg.replyTo;
 
@@ -505,7 +505,7 @@
                 }
 
                 break;
-            case DynamicAndroidClient.MSG_UNREGISTER_LISTENER:
+            case DynamicSystemClient.MSG_UNREGISTER_LISTENER:
                 mClients.remove(msg.replyTo);
                 break;
             default:
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
similarity index 90%
rename from packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
index 03fc773..052fc0a 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.dynandroid;
+package com.android.dynsystem;
 
 import android.gsi.GsiProgress;
 import android.os.AsyncTask;
-import android.os.DynamicAndroidManager;
+import android.os.image.DynamicSystemManager;
 import android.util.Log;
 import android.webkit.URLUtil;
 
@@ -60,9 +60,9 @@
     private final String mUrl;
     private final long mSystemSize;
     private final long mUserdataSize;
-    private final DynamicAndroidManager mDynamicAndroid;
+    private final DynamicSystemManager mDynSystem;
     private final InstallStatusListener mListener;
-    private DynamicAndroidManager.Session mInstallationSession;
+    private DynamicSystemManager.Session mInstallationSession;
 
     private int mResult = NO_RESULT;
 
@@ -70,11 +70,11 @@
 
 
     InstallationAsyncTask(String url, long systemSize, long userdataSize,
-            DynamicAndroidManager dynAndroid, InstallStatusListener listener) {
+            DynamicSystemManager dynSystem, InstallStatusListener listener) {
         mUrl = url;
         mSystemSize = systemSize;
         mUserdataSize = userdataSize;
-        mDynamicAndroid = dynAndroid;
+        mDynSystem = dynSystem;
         mListener = listener;
     }
 
@@ -98,7 +98,7 @@
 
             Thread thread = new Thread(() -> {
                 mInstallationSession =
-                        mDynamicAndroid.startInstallation(mSystemSize, mUserdataSize);
+                        mDynSystem.startInstallation(mSystemSize, mUserdataSize);
             });
 
 
@@ -106,12 +106,12 @@
 
             while (thread.isAlive()) {
                 if (isCancelled()) {
-                    boolean aborted = mDynamicAndroid.abort();
-                    Log.d(TAG, "Called DynamicAndroidManager.abort(), result = " + aborted);
+                    boolean aborted = mDynSystem.abort();
+                    Log.d(TAG, "Called DynamicSystemManager.abort(), result = " + aborted);
                     return RESULT_OK;
                 }
 
-                GsiProgress progress = mDynamicAndroid.getInstallationProgress();
+                GsiProgress progress = mDynSystem.getInstallationProgress();
                 installedSize = progress.bytes_processed;
 
                 if (installedSize > reportedInstalledSize + minStepToReport) {
@@ -146,7 +146,7 @@
                         ? bytes : Arrays.copyOf(bytes, numBytesRead);
 
                 if (!mInstallationSession.write(writeBuffer)) {
-                    throw new IOException("Failed write() to DynamicAndroid");
+                    throw new IOException("Failed write() to DynamicSystem");
                 }
 
                 installedSize += numBytesRead;
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/VerificationActivity.java
similarity index 87%
rename from packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
rename to packages/DynamicSystemInstallationService/src/com/android/dynandroid/VerificationActivity.java
index c18c4fe..f05930f 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/VerificationActivity.java
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-package com.android.dynandroid;
+package com.android.dynsystem;
 
-import static android.content.DynamicAndroidClient.KEY_SYSTEM_SIZE;
-import static android.content.DynamicAndroidClient.KEY_SYSTEM_URL;
-import static android.content.DynamicAndroidClient.KEY_USERDATA_SIZE;
+import static android.os.image.DynamicSystemClient.KEY_SYSTEM_SIZE;
+import static android.os.image.DynamicSystemClient.KEY_SYSTEM_URL;
+import static android.os.image.DynamicSystemClient.KEY_USERDATA_SIZE;
 
 import android.app.Activity;
 import android.app.KeyguardManager;
 import android.content.Context;
-import android.content.DynamicAndroidClient;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.os.image.DynamicSystemClient;
 import android.util.Log;
 
 
@@ -88,8 +88,8 @@
         sVerifiedUrl = url;
 
         // start service
-        Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
-        intent.setAction(DynamicAndroidClient.ACTION_START_INSTALL);
+        Intent intent = new Intent(this, DynamicSystemInstallationService.class);
+        intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
         intent.putExtra(KEY_SYSTEM_URL, url);
         intent.putExtra(KEY_SYSTEM_SIZE, systemSize);
         intent.putExtra(KEY_USERDATA_SIZE, userdataSize);
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 8872147..01cd00a 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -29,6 +29,7 @@
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
         "datastallprotosnano",
+        "networkstackprotosnano",
     ],
     manifest: "AndroidManifestBase.xml",
 }
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index a90db11..b0a7923 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -19,6 +19,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack"
           android:sharedUserId="android.uid.networkstack">
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
     <application>
@@ -28,4 +29,4 @@
             </intent-filter>
         </service>
     </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index 621d30c..f69e4b2 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,7 +20,6 @@
           package="com.android.networkstack"
           android:versionCode="11"
           android:versionName="Q-initial">
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/packages/NetworkStack/AndroidManifest_InProcess.xml b/packages/NetworkStack/AndroidManifest_InProcess.xml
index 48fcecd..275cd02 100644
--- a/packages/NetworkStack/AndroidManifest_InProcess.xml
+++ b/packages/NetworkStack/AndroidManifest_InProcess.xml
@@ -20,6 +20,7 @@
           package="com.android.networkstack.inprocess"
           android:sharedUserId="android.uid.system"
           android:process="system">
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
     <application>
         <service android:name="com.android.server.NetworkStackService" android:process="system">
             <intent-filter>
@@ -27,4 +28,4 @@
             </intent-filter>
         </service>
     </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 61dc966..346ac68 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -897,7 +897,7 @@
         // accompanying code in IpReachabilityMonitor) is unreachable.
         final boolean ignoreIPv6ProvisioningLoss =
                 mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
-                && mCm.getAvoidBadWifi();
+                && mCm.shouldAvoidBadWifi();
 
         // Additionally:
         //
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
index e73cba6..3aa6933 100644
--- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
@@ -332,7 +332,7 @@
     }
 
     private boolean avoidingBadLinks() {
-        return !mUsingMultinetworkPolicyTracker || mCm.getAvoidBadWifi();
+        return !mUsingMultinetworkPolicyTracker || mCm.shouldAvoidBadWifi();
     }
 
     public void probeAll() {
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index a69b412..62535b6 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -15,7 +15,6 @@
     <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
-    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
diff --git a/packages/PackageInstaller/res/layout/uninstall_content_view.xml b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
index 2f8966c..5666c0e 100644
--- a/packages/PackageInstaller/res/layout/uninstall_content_view.xml
+++ b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
@@ -36,16 +36,6 @@
         style="@android:style/TextAppearance.Material.Subhead" />
 
     <CheckBox
-        android:id="@+id/clearContributedFiles"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginStart="-8dp"
-        android:paddingLeft="8sp"
-        android:visibility="gone"
-        style="@android:style/TextAppearance.Material.Subhead" />
-
-    <CheckBox
         android:id="@+id/keepData"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index a05a219..797656e 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -119,8 +119,6 @@
     <string name="uninstall_update_text">Replace this app with the factory version? All data will be removed.</string>
     <!--  [CHAR LIMIT=none] -->
     <string name="uninstall_update_text_multiuser">Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles.</string>
-    <!-- Label of a checkbox that allows to remove the files contributed by app during uninstall [CHAR LIMIT=none] -->
-    <string name="uninstall_remove_contributed_files">Also remove <xliff:g id="size" example="1.5MB">%1$s</xliff:g> of associated media files.</string>
     <!-- Label of a checkbox that allows to keep the data (e.g. files, settings) of the app on uninstall [CHAR LIMIT=none] -->
     <string name="uninstall_keep_data">Keep <xliff:g id="size" example="1.5MB">%1$s</xliff:g> of app data.</string>
 
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
index 63d8c5a8..c4dceb4 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
@@ -50,8 +50,6 @@
             "com.android.packageinstaller.ACTION_UNINSTALL_COMMIT";
 
     static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
-    static final String EXTRA_CLEAR_CONTRIBUTED_FILES =
-            "com.android.packageinstaller.extra.CLEAR_CONTRIBUTED_FILES";
     static final String EXTRA_KEEP_DATA = "com.android.packageinstaller.extra.KEEP_DATA";
 
     private int mUninstallId;
@@ -75,8 +73,6 @@
             if (savedInstanceState == null) {
                 boolean allUsers = getIntent().getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS,
                         false);
-                boolean clearContributedFiles = getIntent().getBooleanExtra(
-                        EXTRA_CLEAR_CONTRIBUTED_FILES, false);
                 boolean keepData = getIntent().getBooleanExtra(EXTRA_KEEP_DATA, false);
                 UserHandle user = getIntent().getParcelableExtra(Intent.EXTRA_USER);
 
@@ -102,7 +98,6 @@
                         broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
                 int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0;
-                flags |= clearContributedFiles ? PackageManager.DELETE_CONTRIBUTED_MEDIA : 0;
                 flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
 
                 try {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index 5419449..be778e9 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -285,7 +285,7 @@
         fragment.show(ft, "dialog");
     }
 
-    public void startUninstallProgress(boolean clearContributedFiles, boolean keepData) {
+    public void startUninstallProgress(boolean keepData) {
         boolean returnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
         CharSequence label = mDialogInfo.appInfo.loadSafeLabel(getPackageManager());
 
@@ -310,8 +310,6 @@
             newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers);
             newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo);
             newIntent.putExtra(UninstallUninstalling.EXTRA_APP_LABEL, label);
-            newIntent.putExtra(UninstallUninstalling.EXTRA_CLEAR_CONTRIBUTED_FILES,
-                    clearContributedFiles);
             newIntent.putExtra(UninstallUninstalling.EXTRA_KEEP_DATA, keepData);
             newIntent.putExtra(PackageInstaller.EXTRA_CALLBACK, mDialogInfo.callback);
 
@@ -362,7 +360,6 @@
                 Log.i(TAG, "Uninstalling extras=" + broadcastIntent.getExtras());
 
                 int flags = mDialogInfo.allUsers ? PackageManager.DELETE_ALL_USERS : 0;
-                flags |= clearContributedFiles ? PackageManager.DELETE_CONTRIBUTED_MEDIA : 0;
                 flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
 
                 ActivityThread.getPackageManager().getPackageInstaller().uninstall(
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index 499da75..0a37cc6 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -36,7 +36,6 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
-import android.provider.MediaStore;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,57 +53,9 @@
         DialogInterface.OnClickListener {
     private static final String LOG_TAG = UninstallAlertDialogFragment.class.getSimpleName();
 
-    private @Nullable CheckBox mClearContributedFiles;
     private @Nullable CheckBox mKeepData;
 
     /**
-     * Get number of bytes of the files contributed by the package.
-     *
-     * @param pkg The package that might have contributed files.
-     * @param user The user the package belongs to.
-     *
-     * @return The number of bytes.
-     */
-    private long getContributedMediaSizeForUser(@NonNull String pkg, @NonNull UserHandle user) {
-        try {
-            return MediaStore.getContributedMediaSize(getContext(), pkg, user);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Cannot determine amount of contributes files for " + pkg
-                    + " (user " + user + ")", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Get number of bytes of the files contributed by the package.
-     *
-     * @param pkg The package that might have contributed files.
-     * @param user The user the package belongs to or {@code null} if files of all users should be
-     *             counted.
-     *
-     * @return The number of bytes.
-     */
-    private long getContributedMediaSize(@NonNull String pkg, @Nullable UserHandle user) {
-        UserManager userManager = getContext().getSystemService(UserManager.class);
-
-        long contributedFileSize = 0;
-
-        if (user == null) {
-            List<UserInfo> users = userManager.getUsers();
-
-            int numUsers = users.size();
-            for (int i = 0; i < numUsers; i++) {
-                contributedFileSize += getContributedMediaSizeForUser(pkg,
-                        UserHandle.of(users.get(i).id));
-            }
-        } else {
-            contributedFileSize = getContributedMediaSizeForUser(pkg, user);
-        }
-
-        return contributedFileSize;
-    }
-
-    /**
      * Get number of bytes of the app data of the package.
      *
      * @param pkg The package that might have app data.
@@ -212,8 +163,6 @@
         dialogBuilder.setNegativeButton(android.R.string.cancel, this);
 
         String pkg = dialogInfo.appInfo.packageName;
-        long contributedFileSize = getContributedMediaSize(pkg,
-                dialogInfo.allUsers ? null : dialogInfo.user);
 
         boolean suggestToKeepAppData;
         try {
@@ -230,28 +179,17 @@
             appDataSize = getAppDataSize(pkg, dialogInfo.allUsers ? null : dialogInfo.user);
         }
 
-        if (contributedFileSize == 0 && appDataSize == 0) {
+        if (appDataSize == 0) {
             dialogBuilder.setMessage(messageBuilder.toString());
         } else {
             LayoutInflater inflater = getContext().getSystemService(LayoutInflater.class);
             ViewGroup content = (ViewGroup) inflater.inflate(R.layout.uninstall_content_view, null);
 
             ((TextView) content.requireViewById(R.id.message)).setText(messageBuilder.toString());
-
-            if (contributedFileSize != 0) {
-                mClearContributedFiles = content.requireViewById(R.id.clearContributedFiles);
-                mClearContributedFiles.setVisibility(View.VISIBLE);
-                mClearContributedFiles.setText(
-                        getString(R.string.uninstall_remove_contributed_files,
-                                formatFileSize(getContext(), contributedFileSize)));
-            }
-
-            if (appDataSize != 0) {
-                mKeepData = content.requireViewById(R.id.keepData);
-                mKeepData.setVisibility(View.VISIBLE);
-                mKeepData.setText(getString(R.string.uninstall_keep_data,
-                        formatFileSize(getContext(), appDataSize)));
-            }
+            mKeepData = content.requireViewById(R.id.keepData);
+            mKeepData.setVisibility(View.VISIBLE);
+            mKeepData.setText(getString(R.string.uninstall_keep_data,
+                    formatFileSize(getContext(), appDataSize)));
 
             dialogBuilder.setView(content);
         }
@@ -263,7 +201,6 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == Dialog.BUTTON_POSITIVE) {
             ((UninstallerActivity) getActivity()).startUninstallProgress(
-                    mClearContributedFiles != null && mClearContributedFiles.isChecked(),
                     mKeepData != null && mKeepData.isChecked());
         } else {
             ((UninstallerActivity) getActivity()).dispatchAborted();
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
index ac5fd76..21d25f5 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAlertFragment.java
@@ -99,7 +99,7 @@
     public void onGuidedActionClicked(GuidedAction action) {
         if (isAdded()) {
             if (action.getId() == GuidedAction.ACTION_ID_OK) {
-                ((UninstallerActivity) getActivity()).startUninstallProgress(false, false);
+                ((UninstallerActivity) getActivity()).startUninstallProgress(false);
                 getActivity().finish();
             } else {
                 ((UninstallerActivity) getActivity()).dispatchAborted();
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index b34f445..b025df4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -185,14 +185,14 @@
      */
     public static void revertScheduleToNoneIfNeeded(Context context) {
         ContentResolver resolver = context.getContentResolver();
-        final int currentMode = Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
-                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+        final int currentMode = Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
         boolean providerConfigured = !TextUtils.isEmpty(context.getString(
                 com.android.internal.R.string.config_batterySaverScheduleProvider));
-        if (currentMode == PowerManager.POWER_SAVER_MODE_DYNAMIC && !providerConfigured) {
+        if (currentMode == PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC && !providerConfigured) {
             Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-            Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
-                    PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+            Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
+                    PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
         }
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a33f9a8..de7202c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -844,7 +844,7 @@
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
                 GlobalSettingsProto.LowPowerMode.TRIGGER_LEVEL_MAX);
         dumpSetting(s, p,
-                Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
+                Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
                 GlobalSettingsProto.LowPowerMode.AUTOMATIC_POWER_SAVER_MODE);
         dumpSetting(s, p,
                 Settings.Global.LOW_POWER_MODE_STICKY,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9e46ad6..7337cdb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -19,6 +19,12 @@
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -33,6 +39,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
@@ -3235,7 +3243,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 176;
+            private static final int SETTINGS_VERSION = 177;
 
             private final int mUserId;
 
@@ -4311,6 +4319,57 @@
                     currentVersion = 176;
                 }
 
+                if (currentVersion == 176) {
+                    // Version 176: Migrate the existing swipe up setting into the resource overlay
+                    //              for the navigation bar interaction mode.
+
+                    final IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
+                            ServiceManager.getService(Context.OVERLAY_SERVICE));
+                    int navBarMode = -1;
+
+                    // Migrate the swipe up setting only if it is set
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting swipeUpSetting = secureSettings.getSettingLocked(
+                            Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED);
+                    if (swipeUpSetting != null && !swipeUpSetting.isNull()) {
+                        navBarMode = swipeUpSetting.getValue().equals("1")
+                                ? NAV_BAR_MODE_2BUTTON
+                                : NAV_BAR_MODE_3BUTTON;
+                    }
+
+                    // Temporary: Only for migration for dogfooders, to be removed
+                    try {
+                        final OverlayInfo info = overlayManager.getOverlayInfo(
+                                "com.android.internal.experiment.navbar.type.inset",
+                                UserHandle.USER_CURRENT);
+                        if (info != null && info.isEnabled()) {
+                            navBarMode = NAV_BAR_MODE_GESTURAL;
+                        }
+                    } catch (RemoteException e) {
+                        // Ingore, fall through
+                    }
+
+                    if (navBarMode != -1) {
+                        try {
+                            overlayManager.setEnabled(NAV_BAR_MODE_3BUTTON_OVERLAY,
+                                    navBarMode == NAV_BAR_MODE_3BUTTON,
+                                    UserHandle.USER_CURRENT);
+                            overlayManager.setEnabled(NAV_BAR_MODE_2BUTTON_OVERLAY,
+                                    navBarMode == NAV_BAR_MODE_2BUTTON,
+                                    UserHandle.USER_CURRENT);
+                            overlayManager.setEnabled(NAV_BAR_MODE_GESTURAL_OVERLAY,
+                                    navBarMode == NAV_BAR_MODE_GESTURAL,
+                                    UserHandle.USER_CURRENT);
+                        } catch (RemoteException e) {
+                            throw new IllegalStateException(
+                                    "Failed to set nav bar interaction mode overlay");
+                        }
+                    }
+
+                    currentVersion = 177;
+                }
+
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 441f88c..d6e61eb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -182,6 +182,10 @@
     <!-- Permission needed to run keyguard manager tests in CTS -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
 
+    <!-- Permission needed to test wallpaper component -->
+    <uses-permission android:name="android.permission.SET_WALLPAPER" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index a9ff21f..1060c7b 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1095,6 +1095,7 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
+                Looper.prepare();
                 zipBugreport(info);
                 sendBugreportNotification(info, takingScreenshot);
                 return null;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6df6c73..d654f5a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -438,7 +438,7 @@
         <activity
             android:name=".media.MediaProjectionPermissionActivity"
             android:exported="true"
-            android:theme="@style/Theme.AlertDialogHost"
+            android:theme="@style/Theme.MediaProjectionAlertDialog"
             android:finishOnCloseSystemDialogs="true"
             android:launchMode="singleTop"
             android:excludeFromRecents="true"
diff --git a/packages/SystemUI/docs/physics-animation-layout-control-methods.png b/packages/SystemUI/docs/physics-animation-layout-control-methods.png
deleted file mode 100644
index e77c676..0000000
--- a/packages/SystemUI/docs/physics-animation-layout-control-methods.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/docs/physics-animation-layout.md b/packages/SystemUI/docs/physics-animation-layout.md
index 300f63a..488c465 100644
--- a/packages/SystemUI/docs/physics-animation-layout.md
+++ b/packages/SystemUI/docs/physics-animation-layout.md
@@ -25,22 +25,74 @@
 Returns a SpringForce instance to use for animations of the given property. This allows the controller to configure stiffness and bounciness values. Since the physics animations internally use SpringForce instances to hold inflight animation values, this method needs to return a new SpringForce instance each time - no constants allowed.
 
 ### Animation Control Methods
-![Diagram of how calls to animateValueForChildAtIndex dispatch to DynamicAnimations.](physics-animation-layout-control-methods.png)
 Once the layout has used the controller’s configuration properties to build the animations, the controller can use them to actually run animations. This is done for two reasons - reacting to a view being added or removed, or responding to another class (such as a touch handler or broadcast receiver) requesting an animation. ```onChildAdded```, ```onChildRemoved```, and ```setChildVisibility``` are called automatically by the layout, giving the controller the opportunity to animate the child in/out/visible/gone. Custom methods are called by anyone with access to the controller instance to do things like expand, collapse, or move the child views.
 
-In either case, the controller has access to the layout’s protected ```animateValueForChildAtIndex(ViewProperty property, int index, float value)``` method. This method is used to actually run an animation.
+In either case, the controller can use `super.animationForChild` to retrieve a `PhysicsPropertyAnimator` instance. This object behaves similarly to the `ViewPropertyAnimator` object you would receive from `View.animate()`. 
 
-For example, moving the first child view to *(100, 200)*:
+#### PhysicsPropertyAnimator
+
+Like `ViewPropertyAnimator`, `PhysicsPropertyAnimator` provides the following methods for animating properties:
+- `alpha(float)`
+- `translationX/Y/Z(float)`
+- `scaleX/Y(float)`
+
+It also provides the following configuration methods:
+- `withStartDelay(int)`, for starting the animation after a given delay.
+- `withStartVelocity(float)`, for starting the animation with the given start velocity.
+- `withPositionStartVelocities(float, float)`, for setting specific start velocities for TRANSLATION_X and TRANSLATION_Y, since these typically differ.
+- `start(Runnable)`, to start the animation, with an optional end action to call when the animations for every property (including chained animations) have completed.
+
+For example, moving the first child view:
 
 ```
-animateValueForChildAtIndex(TRANSLATION_X, 0, 100);
-animateValueForChildAtIndex(TRANSLATION_Y, 0, 200);
+animationForChild(getChildAt(0))
+    .translationX(100)
+    .translationY(200)
+    .setStartDelay(500)
+    .start();
 ```
 
-This would use the physics animations constructed by the layout to spring the view to *(100, 200)*.
+This would use the physics animations constructed by the layout to spring the view to *(100, 200)* after 500ms.
 
 If the controller’s ```getNextAnimationInChain``` method set up the first child’s TRANSLATION_X/Y animations to be chained to the second child’s, this would result in the second child also springing towards (100, 200), plus any offset returned by ```getOffsetForChainedPropertyAnimation```.
 
+##### Advanced Usage
+The animator has additional functionality to reduce the amount of boilerplate required for typical physics animation use cases.
+
+- Often, animations will set starting values for properties before the animation begins. Property methods like `translationX` have an overloaded variant: `translationX(from, to)`. When `start()` is called, the animation will set the view's translationX property to `from` before beginning the animation to `to`.
+- We may want to use different end actions for each property. For example, if we're animating a view to the bottom of the screen, and also fading it out, we might want to perform an action as soon as the fade out is complete. We can use `alpha(to, endAction)`, which will call endAction as soon as the alpha animation is finished. A special case is `position(x, y, endAction)`, where the endAction is called when both translationX and translationY animations have completed.
+
+`PhysicsAnimationController` also provides `animationsForChildrenFromIndex(int, ChildAnimationConfigurator)`. This is a convenience method for starting animations on multiple child views, starting at the given index. The `ChildAnimationConfigurator` is called with a `PhysicsPropertyAnimator` for each child, where calls to methods like `translationX` and `withStartVelocity` can be made. `animationsForChildrenFromIndex` returns a `MultiAnimationStarter` with a single method, `startAll(endAction)`, which starts all of the animations and calls the end action when they have all completed.
+
+##### Examples
+Spring the stack of bubbles (whose animations are chained) to the bottom of the screen, shrinking them to 50% size. Once the first bubble is done shrinking, begin fading them out, and then remove them all from the parent once all bubbles have faded out:
+
+```
+animationForChild(leadBubble)
+    .position(screenCenter, screenBottom)
+    .scaleX(0.5f)
+    .scaleY(0.5f, () -> animationForChild(leadBubble).alpha(0).start(removeAllFromParent))
+    .start();
+```
+
+'Drop in' a child view that was just added to the layout:
+
+```
+animationForChild(newView)
+    .scaleX(1.15f /* from */, 1f /* to */)
+    .scaleY(1.15f /* from */, 1f /* to */)
+    .alpha(0f /* from */, 1f /* to */)
+    .position(posX, posY)
+    .start();
+```
+
+Move every view except for the first to x = (index - 1) * 50, then remove the first view.
+
+```
+animationsForChildrenFromIndex(1, (index, anim) -> anim.translationX((index - 1) * 50))
+    .startAll(removeFirstView);
+```
+
 ## PhysicsAnimationLayout
 The layout itself is a FrameLayout descendant with a few extra methods:
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 3d2f570..0a0530c0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -60,6 +60,7 @@
 
     boolean areCaptionsEnabled();
     void setCaptionsEnabled(boolean isEnabled);
+    boolean isCaptionStreamOptedOut();
 
     void getCaptionsComponentState(boolean fromTooltip);
 
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 5714556..2f2f84a 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -444,15 +444,15 @@
     <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=20] -->
     <string-array name="type_clock_minutes">
         <item>O\u2019Clock</item>
-        <item>O\u2019One</item>
-        <item>O\u2019Two</item>
-        <item>O\u2019Three</item>
-        <item>O\u2019Four</item>
-        <item>O\u2019Five</item>
-        <item>O\u2019Six</item>
-        <item>O\u2019Seven</item>
-        <item>O\u2019Eight</item>
-        <item>O\u2019Nine</item>
+        <item>Oh One</item>
+        <item>Oh Two</item>
+        <item>Oh Three</item>
+        <item>Oh Four</item>
+        <item>Oh Five</item>
+        <item>Oh Six</item>
+        <item>Oh Seven</item>
+        <item>Oh Eight</item>
+        <item>Oh Nine</item>
         <item>Ten</item>
         <item>Eleven</item>
         <item>Twelve</item>
diff --git a/packages/SystemUI/res/color/caption_tint_color_selector.xml b/packages/SystemUI/res/color/caption_tint_color_selector.xml
new file mode 100644
index 0000000..30843ec
--- /dev/null
+++ b/packages/SystemUI/res/color/caption_tint_color_selector.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:sysui="http://schemas.android.com/apk/res-auto">
+    <item sysui:optedOut="true"
+          android:color="?android:attr/colorButtonNormal"/>
+
+    <item android:color="?android:attr/colorAccent"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index 83557f2..8f7a45f 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -128,7 +128,6 @@
                             android:textSize="12sp"
                             android:gravity="center_horizontal"
                             android:accessibilityLiveRegion="polite"
-                            android:contentDescription="@string/accessibility_biometric_dialog_help_area"
                             android:textColor="?android:attr/textColorSecondary"/>
 
                         <LinearLayout
diff --git a/packages/SystemUI/res/layout/bubble_permission_view.xml b/packages/SystemUI/res/layout/bubble_permission_view.xml
index c9d8a91..df5264c 100644
--- a/packages/SystemUI/res/layout/bubble_permission_view.xml
+++ b/packages/SystemUI/res/layout/bubble_permission_view.xml
@@ -58,7 +58,7 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="8dp"
         android:text="@string/bubbles_prompt"
-        style="@*android:style/TextAppearance.Material.Body1" />
+        style="@*android:style/TextAppearance.DeviceDefault.Notification.Title"/>
 
     <!-- Buttons -->
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/media_projection_dialog_title.xml b/packages/SystemUI/res/layout/media_projection_dialog_title.xml
new file mode 100644
index 0000000..c4d784b
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_projection_dialog_title.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2019, 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.
+-->
+
+<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:theme="@style/Theme.MediaProjectionAlertDialog"
+        android:paddingStart="?android:attr/dialogPreferredPadding"
+        android:paddingEnd="?android:attr/dialogPreferredPadding"
+        android:paddingTop="?android:attr/dialogPreferredPadding">
+    <ImageView
+        android:id="@+id/dialog_icon"
+        android:src="@drawable/ic_media_projection_permission"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_marginBottom="20dp"
+        android:layout_centerInParent="true"/>
+    <TextView
+        android:id="@+id/dialog_title"
+        android:gravity="center"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/dialog_icon"
+        android:textColor="?android:attr/colorPrimary"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Title" />
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 669d53b..a02962e 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -30,13 +30,6 @@
     android:clipChildren="false"
     android:clipToPadding="false">
 
-    <View
-        android:id="@+id/qs_footer_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_gravity="top"
-        android:background="?android:attr/dividerHorizontal"/>
-
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -99,7 +92,6 @@
                     android:layout_width="@dimen/multi_user_avatar_expanded_size"
                     android:layout_height="@dimen/multi_user_avatar_expanded_size"
                     android:layout_gravity="center"
-                    android:tint="?android:attr/colorAccent"
                     android:scaleType="centerInside"/>
             </com.android.systemui.statusbar.phone.MultiUserSwitch>
 
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index fa74536..dc31b70 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -19,7 +19,7 @@
     android:id="@+id/quick_qs_status_icons"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginTop="8dp"
+    android:layout_marginTop="@dimen/qs_header_top_margin"
     android:layout_marginBottom="14dp"
     android:layout_marginStart="@dimen/status_bar_padding_start"
     android:layout_marginEnd="@dimen/status_bar_padding_end"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 075f51d..da640fd 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -19,7 +19,9 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_header_tooltip_height"
     android:layout_below="@id/quick_status_bar_system_icons"
-    android:layout_marginTop="12dp">
+    android:layout_marginTop="@dimen/qs_header_top_margin"
+    android:paddingStart="@dimen/status_bar_padding_start"
+    android:paddingEnd="@dimen/status_bar_padding_end">
 
     <TextView
         android:id="@+id/long_press_tooltip"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 1d0a242..d1c80c4 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,6 +15,7 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
@@ -117,16 +118,17 @@
             android:clipToPadding="false"
             android:translationZ="@dimen/volume_dialog_elevation"
             android:background="@drawable/rounded_bg_full">
-            <com.android.keyguard.AlphaOptimizedImageButton
+            <com.android.systemui.volume.CaptionsToggleImageButton
                 android:id="@+id/odi_captions_icon"
                 android:src="@drawable/ic_volume_odi_captions_disabled"
                 style="@style/VolumeButtons"
                 android:background="@drawable/rounded_ripple"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:tint="@color/accent_tint_color_selector"
+                android:tint="@color/caption_tint_color_selector"
                 android:layout_gravity="center"
-                android:soundEffectsEnabled="false" />
+                android:soundEffectsEnabled="false"
+                sysui:optedOut="false"/>
         </FrameLayout>
 
     </LinearLayout>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 77e79c9..e768939 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -33,7 +33,6 @@
     <integer name="quick_settings_num_columns">4</integer>
     <bool name="quick_settings_wide">true</bool>
     <dimen name="qs_detail_margin_top">0dp</dimen>
-    <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
 
     <dimen name="volume_tool_tip_right_margin">136dp</dimen>
     <dimen name="volume_tool_tip_top_margin">12dp</dimen>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 27d2bcd..e0bcf24 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -146,5 +146,9 @@
         <attr name="showAirplaneMode" format="boolean" />
     </declare-styleable>
 
+    <declare-styleable name="CaptionsToggleImageButton">
+        <attr name="optedOut" format="boolean" />
+    </declare-styleable>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 27cebcc..1da1405 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -206,10 +206,10 @@
     <dimen name="status_bar_icon_padding">0dp</dimen>
 
     <!-- the padding on the start of the statusbar -->
-    <dimen name="status_bar_padding_start">6dp</dimen>
+    <dimen name="status_bar_padding_start">8dp</dimen>
 
     <!-- the padding on the end of the statusbar -->
-    <dimen name="status_bar_padding_end">6dp</dimen>
+    <dimen name="status_bar_padding_end">8dp</dimen>
 
     <!-- the radius of the overflow dot in the status bar -->
     <dimen name="overflow_dot_radius">2dp</dimen>
@@ -433,7 +433,7 @@
     <dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
     <dimen name="qs_header_tooltip_height">18dp</dimen>
     <dimen name="qs_header_alarm_icon_size">18dp</dimen>
-    <dimen name="qs_header_mobile_icon_size">18dp</dimen>
+    <dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
     <dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
     <dimen name="qs_header_separator_width">8dp</dimen>
     <dimen name="qs_header_carrier_separator_width">6dp</dimen>
@@ -442,7 +442,8 @@
     <dimen name="qs_footer_padding_start">16dp</dimen>
     <dimen name="qs_footer_padding_end">16dp</dimen>
     <dimen name="qs_footer_icon_size">16dp</dimen>
-    <dimen name="qs_paged_tile_layout_padding_bottom">16dp</dimen>
+    <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
+    <dimen name="qs_header_top_margin">12dp</dimen>
 
     <dimen name="qs_notif_collapsed_space">64dp</dimen>
 
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 05cf040..501b1b5 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -111,13 +111,14 @@
     <!-- Optional cancel button on Keyguard -->
     <item type="id" name="cancel_button"/>
 
-    <!-- For saving DynamicAnimation physics animations as view tags. -->
+    <!-- For saving PhysicsAnimationLayout animations/animators as view tags. -->
     <item type="id" name="translation_x_dynamicanimation_tag"/>
     <item type="id" name="translation_y_dynamicanimation_tag"/>
     <item type="id" name="translation_z_dynamicanimation_tag"/>
     <item type="id" name="alpha_dynamicanimation_tag"/>
     <item type="id" name="scale_x_dynamicanimation_tag"/>
     <item type="id" name="scale_y_dynamicanimation_tag"/>
+    <item type="id" name="physics_animator_tag"/>
 
     <!-- Global Actions Menu -->
     <item type="id" name="global_actions_view" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f8bec4a..62309fd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -279,8 +279,6 @@
     <!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
     <string name="cancel">Cancel</string>
 
-    <!-- Content description for the error/help message are when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_biometric_dialog_help_area">Help message area</string>
     <!-- Message shown when a biometric is authenticated, asking the user to confirm authentication [CHAR LIMIT=30] -->
     <string name="biometric_dialog_confirm">Confirm</string>
     <!-- Button name on BiometricPrompt shown when a biometric is detected but not authenticated. Tapping the button resumes authentication [CHAR_LIMIT=30] -->
@@ -551,11 +549,11 @@
     <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_alarms_on">alarms only</string>
      <!-- Content description of the do not disturb tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd">Do not disturb.</string>
+    <string name="accessibility_quick_settings_dnd">Do Not Disturb.</string>
     <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+    <string name="accessibility_quick_settings_dnd_changed_off">Do Not Disturb turned off.</string>
     <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
+    <string name="accessibility_quick_settings_dnd_changed_on">Do Not Disturb turned on.</string>
     <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth">Bluetooth.</string>
     <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -701,7 +699,7 @@
     <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
     <string name="quick_settings_header_onboarding_text">Touch &amp; hold icons for more options</string>
     <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_dnd_label">Do not disturb</string>
+    <string name="quick_settings_dnd_label">Do Not Disturb</string>
     <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_priority_label">Priority only</string>
     <!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
@@ -1816,14 +1814,14 @@
     <string name="tuner_full_zen_title">Show with volume controls</string>
 
     <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
-    <string name="volume_and_do_not_disturb">Do not disturb</string>
+    <string name="volume_and_do_not_disturb">Do Not Disturb</string>
 
     <!-- SysUI Tuner: Switch to control whether volume buttons enter/exit do
          not disturb [CHAR LIMIT=60] -->
     <string name="volume_dnd_silent">Volume buttons shortcut</string>
 
     <!-- SysUI Tuner: Switch to control volume up behavior [CHAR LIMIT=60] -->
-    <string name="volume_up_silent">Exit do not disturb on volume up</string>
+    <string name="volume_up_silent">Exit Do Not Disturb on volume up</string>
 
     <!-- Name of the battery icon in status bar [CHAR LIMIT=30] -->
     <string name="battery">Battery</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1c13750..a6a6e6b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -353,13 +353,13 @@
     <style name="AutoSizingList">
         <item name="enableAutoSizing">true</item>
     </style>
-    <style name="Theme.AlertDialogHost" parent="android:Theme.DeviceDefault">
+    <style name="Theme.MediaProjectionAlertDialog" parent="android:Theme.DeviceDefault">
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowIsFloating">true</item>
-        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:backgroundDimEnabled">true</item>
         <item name="android:alertDialogTheme">@style/Theme.SystemUI.Dialog.Alert</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ce65b5a..fd92e9e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,5 +1,7 @@
 package com.android.keyguard;
 
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -24,8 +26,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
 import com.android.keyguard.clock.ClockManager;
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.ClockPlugin;
@@ -37,37 +39,65 @@
 import java.util.Arrays;
 import java.util.TimeZone;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 /**
  * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
  */
 public class KeyguardClockSwitch extends RelativeLayout {
 
+    /**
+     * Controller used to track StatusBar state to know when to show the big_clock_container.
+     */
+    private final StatusBarStateController mStatusBarStateController;
+
+    /**
+     * Color extractor used to apply colors from wallpaper to custom clock faces.
+     */
+    private final SysuiColorExtractor mSysuiColorExtractor;
+
+    /**
+     * Manager used to know when to show a custom clock face.
+     */
+    private final ClockManager mClockManager;
+
+    /**
+     * Layout transition that scales the default clock face.
+     */
     private final Transition mTransition;
+
     /**
      * Optional/alternative clock injected via plugin.
      */
     private ClockPlugin mClockPlugin;
+
     /**
      * Default clock.
      */
     private TextClock mClockView;
+
     /**
      * Frame for default and custom clock.
      */
     private FrameLayout mSmallClockFrame;
+
     /**
      * Container for big custom clock.
      */
     private ViewGroup mBigClockContainer;
+
     /**
      * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
      * show it below the alternate clock.
      */
     private View mKeyguardStatusArea;
+
     /**
      * Maintain state so that a newly connected plugin can be initialized.
      */
     private float mDarkAmount;
+
     /**
      * If the Keyguard Slice has a header (big center-aligned text.)
      */
@@ -96,22 +126,20 @@
      *
      * The color palette changes when the wallpaper is changed.
      */
-    private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
+    private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
         if ((which & WallpaperManager.FLAG_LOCK) != 0) {
-            if (extractor instanceof SysuiColorExtractor) {
-                updateColors((SysuiColorExtractor) extractor);
-            } else {
-                updateColors(Dependency.get(SysuiColorExtractor.class));
-            }
+            updateColors();
         }
     };
 
-    public KeyguardClockSwitch(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardClockSwitch(Context context, AttributeSet attrs) {
+    @Inject
+    public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
+            StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
+            ClockManager clockManager) {
         super(context, attrs);
+        mStatusBarStateController = statusBarStateController;
+        mSysuiColorExtractor = colorExtractor;
+        mClockManager = clockManager;
         mTransition = new ClockBoundsTransition();
     }
 
@@ -133,22 +161,18 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
-        StatusBarStateController stateController = Dependency.get(StatusBarStateController.class);
-        stateController.addCallback(mStateListener);
-        mStateListener.onStateChanged(stateController.getState());
-        SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class);
-        colorExtractor.addOnColorsChangedListener(mColorsListener);
-        updateColors(colorExtractor);
+        mClockManager.addOnClockChangedListener(mClockChangedListener);
+        mStatusBarStateController.addCallback(mStateListener);
+        mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
+        updateColors();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
-        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
-        Dependency.get(SysuiColorExtractor.class)
-                .removeOnColorsChangedListener(mColorsListener);
+        mClockManager.removeOnClockChangedListener(mClockChangedListener);
+        mStatusBarStateController.removeCallback(mStateListener);
+        mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
         setClockPlugin(null);
     }
 
@@ -271,14 +295,11 @@
         return mClockView.getTextSize();
     }
 
+    /**
+     * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
+     */
     public void refresh() {
         mClockView.refresh();
-    }
-
-    /**
-     * Notifies that time tick alarm from doze service fired.
-     */
-    public void dozeTimeTick() {
         if (mClockPlugin != null) {
             mClockPlugin.onTimeTick();
         }
@@ -293,9 +314,9 @@
         }
     }
 
-    private void updateColors(SysuiColorExtractor colorExtractor) {
-        ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                true);
+    private void updateColors() {
+        ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
+                WallpaperManager.FLAG_LOCK, true);
         mSupportsDarkText = colors.supportsDarkText();
         mColorPalette = colors.getColorPalette();
         if (mClockPlugin != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 9dd9717..ae8bc52 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -28,9 +28,12 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 
+import com.android.systemui.util.InjectionInflationController;
+
 // TODO(multi-display): Support multiple external displays
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
@@ -38,6 +41,7 @@
 
     private final MediaRouter mMediaRouter;
     private final DisplayManager mDisplayService;
+    private final InjectionInflationController mInjectableInflater;
     private final Context mContext;
 
     private boolean mShowing;
@@ -75,8 +79,10 @@
         }
     };
 
-    public KeyguardDisplayManager(Context context) {
+    public KeyguardDisplayManager(Context context,
+            InjectionInflationController injectableInflater) {
         mContext = context;
+        mInjectableInflater = injectableInflater;
         mMediaRouter = mContext.getSystemService(MediaRouter.class);
         mDisplayService = mContext.getSystemService(DisplayManager.class);
         mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -110,7 +116,7 @@
         final int displayId = display.getDisplayId();
         Presentation presentation = mPresentations.get(displayId);
         if (presentation == null) {
-            presentation = new KeyguardPresentation(mContext, display);
+            presentation = new KeyguardPresentation(mContext, display, mInjectableInflater);
             presentation.setOnDismissListener(dialog -> {
                 if (null != mPresentations.get(displayId)) {
                     mPresentations.remove(displayId);
@@ -201,6 +207,7 @@
     private final static class KeyguardPresentation extends Presentation {
         private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
         private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+        private final InjectionInflationController mInjectableInflater;
         private View mClock;
         private int mUsableWidth;
         private int mUsableHeight;
@@ -217,8 +224,10 @@
             }
         };
 
-        KeyguardPresentation(Context context, Display display) {
+        KeyguardPresentation(Context context, Display display,
+                InjectionInflationController injectionInflater) {
             super(context, display, R.style.keyguard_presentation_theme);
+            mInjectableInflater = injectionInflater;
             getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
             setCancelable(false);
         }
@@ -239,7 +248,9 @@
             mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
             mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
 
-            setContentView(R.layout.keyguard_presentation);
+            LayoutInflater inflater = mInjectableInflater.injectable(
+                    LayoutInflater.from(getContext()));
+            setContentView(inflater.inflate(R.layout.keyguard_presentation, null));
             mClock = findViewById(R.id.clock);
 
             // Avoid screen burn in
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index e87b313..52b766d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -47,6 +47,17 @@
     private static final int USER_TYPE_WORK_PROFILE = 2;
     private static final int USER_TYPE_SECONDARY_USER = 3;
 
+    // Bouncer is dismissed due to no security.
+    private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
+    // Bouncer is dismissed due to pin, password or pattern entered.
+    private static final int BOUNCER_DISMISS_PASSWORD = 1;
+    // Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
+    private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
+    // Bouncer is dismissed due to extended access granted.
+    private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
+    // Bouncer is dismissed due to sim card unlock code entered.
+    private static final int BOUNCER_DISMISS_SIM = 4;
+
     private KeyguardSecurityModel mSecurityModel;
     private LockPatternUtils mLockPatternUtils;
 
@@ -328,12 +339,18 @@
         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
         boolean finish = false;
         boolean strongAuth = false;
-        if (mUpdateMonitor.getUserCanSkipBouncer(targetUserId)) {
+        int eventSubtype = -1;
+        if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
             finish = true;
+            eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
+        } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
+            finish = true;
+            eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
         } else if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
             if (SecurityMode.None == securityMode) {
                 finish = true; // no security required
+                eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
             } else {
                 showSecurityScreen(securityMode); // switch to the alternate security view
             }
@@ -344,6 +361,7 @@
                 case PIN:
                     strongAuth = true;
                     finish = true;
+                    eventSubtype = BOUNCER_DISMISS_PASSWORD;
                     break;
 
                 case SimPin:
@@ -353,6 +371,7 @@
                     if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser())) {
                         finish = true;
+                        eventSubtype = BOUNCER_DISMISS_SIM;
                     } else {
                         showSecurityScreen(securityMode);
                     }
@@ -364,6 +383,10 @@
                     break;
             }
         }
+        if (eventSubtype != -1) {
+            mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
+                    .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
+        }
         if (finish) {
             mSecurityCallback.finish(strongAuth, targetUserId);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 808e264..0369e4c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -214,7 +214,6 @@
     public void dozeTimeTick() {
         refreshTime();
         mKeyguardSlice.refresh();
-        mClockView.dozeTimeTick();
     }
 
     private void refreshTime() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 63f8cd6..fa39ccd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -886,15 +886,22 @@
 
 
     public boolean getUserCanSkipBouncer(int userId) {
-        boolean fingerprintOrFace = mUserFingerprintAuthenticated.get(userId)
-                || mUserFaceAuthenticated.get(userId);
-        return getUserHasTrust(userId) || (fingerprintOrFace && isUnlockingWithBiometricAllowed());
+        return getUserHasTrust(userId) || getUserUnlockedWithBiometric(userId);
     }
 
     public boolean getUserHasTrust(int userId) {
         return !isTrustDisabled(userId) && mUserHasTrust.get(userId);
     }
 
+    /**
+     * Returns whether the user is unlocked with biometrics.
+     */
+    public boolean getUserUnlockedWithBiometric(int userId) {
+        boolean fingerprintOrFace = mUserFingerprintAuthenticated.get(userId)
+                || mUserFaceAuthenticated.get(userId);
+        return fingerprintOrFace && isUnlockingWithBiometricAllowed();
+    }
+
     public boolean getUserTrustIsManaged(int userId) {
         return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index 870ac87..32c1242 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -141,6 +141,8 @@
     @Override
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
+        mDigitalClock.refresh();
+        mLockClock.refresh();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
index 7401819..34b2fd8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -136,6 +136,8 @@
     @Override
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
+        mDigitalClock.refresh();
+        mLockClock.refresh();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 14e910f..8e3afd8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -43,6 +43,7 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
@@ -457,30 +458,38 @@
     void updateHeight() {
         if (usingActivityView()) {
             Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
-            int desiredHeight;
+            float desiredHeight;
             if (data == null) {
                 // This is a contentIntent based bubble, lets allow it to be the max height
                 // as it was forced into this mode and not prepared to be small
                 desiredHeight = mStackView.getMaxExpandedHeight();
             } else {
-                desiredHeight = data.getDesiredHeight() > 0
-                        ? data.getDesiredHeight()
-                        : mMinHeight;
+                boolean useRes = data.getDesiredHeightResId() != 0;
+                float desiredPx;
+                if (useRes) {
+                    desiredPx = getDimenForPackageUser(data.getDesiredHeightResId(),
+                            mEntry.notification.getPackageName(),
+                            mEntry.notification.getUser().getIdentifier());
+                } else {
+                    desiredPx = data.getDesiredHeight()
+                            * getContext().getResources().getDisplayMetrics().density;
+                }
+                desiredHeight = desiredPx > 0 ? desiredPx : mMinHeight;
             }
             int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
                     ? mHeaderHeight
                     : mPermissionHeight;
             int max = mStackView.getMaxExpandedHeight() - chromeHeight - mPointerView.getHeight()
                     - mPointerMargin;
-            int height = Math.min(desiredHeight, max);
+            float height = Math.min(desiredHeight, max);
             height = Math.max(height, mMinHeight);
             LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
             mNeedsNewHeight =  lp.height != height;
             if (!mKeyboardVisible) {
                 // If the keyboard is visible... don't adjust the height because that will cause
                 // a configuration change and the keyboard will be lost.
-                lp.height = height;
-                mBubbleHeight = height;
+                lp.height = (int) height;
+                mBubbleHeight = (int) height;
                 mActivityView.setLayoutParams(lp);
                 mNeedsNewHeight = false;
             }
@@ -712,4 +721,23 @@
                 mStackView.getNormalizedXPosition(),
                 mStackView.getNormalizedYPosition());
     }
+
+    private int getDimenForPackageUser(int resId, String pkg, int userId) {
+        Resources r;
+        if (pkg != null) {
+            try {
+                if (userId == UserHandle.USER_ALL) {
+                    userId = UserHandle.USER_SYSTEM;
+                }
+                r = mPm.getResourcesForApplicationAsUser(pkg, userId);
+                return r.getDimensionPixelSize(resId);
+            } catch (PackageManager.NameNotFoundException ex) {
+                // Uninstalled, don't care
+            } catch (Resources.NotFoundException e) {
+                // Invalid res id, return 0 and user our default
+                Log.e(TAG, "Couldn't find desired height res id", e);
+            }
+        }
+        return 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 40e08be..d601e63 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -104,16 +104,23 @@
      * @return The y-value to which the bubbles were expanded, in case that's useful.
      */
     public float expandFromStack(PointF collapseTo, Runnable after) {
+        animationsForChildrenFromIndex(
+                0, /* startIndex */
+                new ChildAnimationConfigurator() {
+                    // How much to translate the next bubble, so that it is not overlapping the
+                    // previous one.
+                    float mTranslateNextBubbleXBy = mBubblePaddingPx;
+
+                    @Override
+                    public void configureAnimationForChildAtIndex(
+                            int index, PhysicsAnimationLayout.PhysicsPropertyAnimator animation) {
+                        animation.position(mTranslateNextBubbleXBy, getExpandedY());
+                        mTranslateNextBubbleXBy += mBubbleSizePx + mBubblePaddingPx;
+                    }
+            })
+            .startAll(after);
+
         mCollapseToPoint = collapseTo;
-
-        // How much to translate the next bubble, so that it is not overlapping the previous one.
-        float translateNextBubbleXBy = mBubblePaddingPx;
-        for (int i = 0; i < mLayout.getChildCount(); i++) {
-            mLayout.animatePositionForChildAtIndex(i, translateNextBubbleXBy, getExpandedY());
-            translateNextBubbleXBy += mBubbleSizePx + mBubblePaddingPx;
-        }
-
-        runAfterTranslationsEnd(after);
         return getExpandedY();
     }
 
@@ -121,13 +128,14 @@
     public void collapseBackToStack(Runnable after) {
         // Stack to the left if we're going to the left, or right if not.
         final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapseToPoint.x) ? -1 : 1;
-        for (int i = 0; i < mLayout.getChildCount(); i++) {
-            mLayout.animatePositionForChildAtIndex(
-                    i,
-                    mCollapseToPoint.x + (sideMultiplier * i * mStackOffsetPx), mCollapseToPoint.y);
-        }
 
-        runAfterTranslationsEnd(after);
+        animationsForChildrenFromIndex(
+                0, /* startIndex */
+                (index, animation) ->
+                    animation.position(
+                            mCollapseToPoint.x + (sideMultiplier * index * mStackOffsetPx),
+                            mCollapseToPoint.y))
+            .startAll(after /* endAction */);
     }
 
     /** Prepares the given bubble to be dragged out. */
@@ -164,20 +172,10 @@
     public void snapBubbleBack(View bubbleView, float velX, float velY) {
         final int index = mLayout.indexOfChild(bubbleView);
 
-        // Snap the bubble back, respecting its current velocity.
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X, index, getXForChildAtIndex(index), velX);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_Y, index, getExpandedY(), velY);
-        mLayout.setEndListenerForProperties(
-                mLayout.new OneTimeMultiplePropertyEndListener() {
-                    @Override
-                    void onAllAnimationsForPropertiesEnd() {
-                        // Reset Z translation once the bubble is done snapping back.
-                        bubbleView.setTranslationZ(0f);
-                    }
-                },
-                DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
+        animationForChildAtIndex(index)
+                .position(getXForChildAtIndex(index), getExpandedY())
+                .withPositionStartVelocities(velX, velY)
+                .start(() -> bubbleView.setTranslationZ(0f) /* after */);
 
         animateStackByBubbleWidthsStartingFrom(
                 /* numBubbleWidths */ 0, /* startIndex */ index + 1);
@@ -202,12 +200,8 @@
      */
     public void updateYPosition(Runnable after) {
         if (mLayout == null) return;
-
-        for (int i = 0; i < mLayout.getChildCount(); i++) {
-            boolean isLast = i == mLayout.getChildCount() - 1;
-            mLayout.animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_Y, i,
-                    getExpandedY(), isLast ? after : null);
-        }
+        animationsForChildrenFromIndex(
+                0, (i, anim) -> anim.translationY(getExpandedY())).startAll(after);
     }
 
     /**
@@ -216,12 +210,11 @@
      * positions.
      */
     private void animateStackByBubbleWidthsStartingFrom(int numBubbleWidths, int startIndex) {
-        for (int i = startIndex; i < mLayout.getChildCount(); i++) {
-            mLayout.animateValueForChildAtIndex(
-                    DynamicAnimation.TRANSLATION_X,
-                    i,
-                    getXForChildAtIndex(i + numBubbleWidths));
-        }
+        animationsForChildrenFromIndex(
+                startIndex,
+                (index, animation) ->
+                        animation.translationX(getXForChildAtIndex(index + numBubbleWidths)))
+            .startAll();
     }
 
     /** The Y value of the row of expanded bubbles. */
@@ -248,21 +241,6 @@
         }
     }
 
-    /** Runs the given Runnable after all translation-related animations have ended. */
-    private void runAfterTranslationsEnd(Runnable after) {
-        DynamicAnimation.OnAnimationEndListener allEndedListener =
-                (animation, canceled, value, velocity) -> {
-                    if (!mLayout.arePropertiesAnimating(
-                            DynamicAnimation.TRANSLATION_X,
-                            DynamicAnimation.TRANSLATION_Y)) {
-                        after.run();
-                    }
-                };
-
-        mLayout.setEndListenerForProperty(allEndedListener, DynamicAnimation.TRANSLATION_X);
-        mLayout.setEndListenerForProperty(allEndedListener, DynamicAnimation.TRANSLATION_Y);
-    }
-
     @Override
     Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
         return Sets.newHashSet(
@@ -295,8 +273,12 @@
         // Pop in from the top.
         // TODO: Reverse this when bubbles are at the bottom.
         child.setTranslationX(getXForChildAtIndex(index));
-        child.setTranslationY(getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR);
-        mLayout.animateValueForChild(DynamicAnimation.TRANSLATION_Y, child, getExpandedY());
+
+        animationForChild(child)
+                .translationY(
+                        getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
+                        getExpandedY() /* to */)
+                .start();
         animateBubblesAfterIndexToCorrectX(index);
     }
 
@@ -304,36 +286,26 @@
     void onChildRemoved(View child, int index, Runnable finishRemoval) {
         // Bubble pops out to the top.
         // TODO: Reverse this when bubbles are at the bottom.
-        mLayout.animateValueForChild(
-                DynamicAnimation.ALPHA, child, 0f, finishRemoval);
+
+        final PhysicsAnimationLayout.PhysicsPropertyAnimator animator = animationForChild(child);
+        animator.alpha(0f, finishRemoval /* endAction */);
 
         // If we're removing the dragged-out bubble, that means it got dismissed.
         if (child.equals(mBubbleDraggingOut)) {
-            // Throw it to the bottom of the screen, towards the center horizontally.
-            mLayout.animateValueForChild(
-                    DynamicAnimation.TRANSLATION_X,
-                    child,
-                    mLayout.getWidth() / 2f - mBubbleSizePx / 2f,
-                    mBubbleDraggingOutVelX);
-            mLayout.animateValueForChild(
-                    DynamicAnimation.TRANSLATION_Y,
-                    child,
-                    mLayout.getHeight() + mBubbleSizePx,
-                    mBubbleDraggingOutVelY);
-
-            // Scale it down a bit so it looks like it's disappearing.
-            mLayout.animateValueForChild(DynamicAnimation.SCALE_X, child, ANIMATE_SCALE_PERCENT);
-            mLayout.animateValueForChild(DynamicAnimation.SCALE_Y, child, ANIMATE_SCALE_PERCENT);
+            animator.position(
+                            mLayout.getWidth() / 2f - mBubbleSizePx / 2f,
+                            mLayout.getHeight() + mBubbleSizePx)
+                    .withPositionStartVelocities(mBubbleDraggingOutVelX, mBubbleDraggingOutVelY)
+                    .scaleX(ANIMATE_SCALE_PERCENT)
+                    .scaleY(ANIMATE_SCALE_PERCENT);
 
             mBubbleDraggingOut = null;
         } else {
-            // If we're removing some random bubble just throw it off the top.
-            mLayout.animateValueForChild(
-                    DynamicAnimation.TRANSLATION_Y,
-                    child,
-                    getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR);
+            animator.translationY(getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR);
         }
 
+        animator.start();
+
         // Animate all the other bubbles to their new positions sans this bubble.
         animateBubblesAfterIndexToCorrectX(index);
     }
@@ -346,12 +318,9 @@
             child.setVisibility(View.VISIBLE);
         }
 
-        // Fade in.
-        mLayout.animateValueForChild(
-                DynamicAnimation.ALPHA,
-                child,
-                /* value */ visibility == View.GONE ? 0f : 1f,
-                () -> super.setChildVisibility(child, index, visibility));
+        animationForChild(child)
+                .alpha(visibility == View.GONE ? 0f : 1f)
+                .start(() -> super.setChildVisibility(child, index, visibility) /* after */);
     }
 
     /**
@@ -365,8 +334,9 @@
             // Don't animate the dragging out bubble, or it'll jump around while being dragged. It
             // will be snapped to the correct X value after the drag (if it's not dismissed).
             if (!bubble.equals(mBubbleDraggingOut)) {
-                mLayout.animateValueForChild(
-                        DynamicAnimation.TRANSLATION_X, bubble, getXForChildAtIndex(i));
+                animationForChild(bubble)
+                        .translationX(getXForChildAtIndex(i))
+                        .start();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index dfdcfc9..2fa87d8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -27,8 +27,11 @@
 
 import com.android.systemui.R;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -46,6 +49,35 @@
      */
     abstract static class PhysicsAnimationController {
 
+        /** Configures a given {@link PhysicsPropertyAnimator} for a view at the given index. */
+        interface ChildAnimationConfigurator {
+
+            /**
+             * Called to configure the animator for the view at the given index.
+             *
+             * This method should make use of methods such as
+             * {@link PhysicsPropertyAnimator#translationX} and
+             * {@link PhysicsPropertyAnimator#withStartDelay} to configure the animation.
+             *
+             * Implementations should not call {@link PhysicsPropertyAnimator#start}, this will
+             * happen elsewhere after configuration is complete.
+             */
+            void configureAnimationForChildAtIndex(int index, PhysicsPropertyAnimator animation);
+        }
+
+        /**
+         * Returned by {@link #animationsForChildrenFromIndex} to allow starting multiple animations
+         * on multiple child views at the same time.
+         */
+        interface MultiAnimationStarter {
+
+            /**
+             * Start all animations and call the given end actions once all animations have
+             * completed.
+             */
+            void startAll(Runnable... endActions);
+        }
+
         /**
          * Constant to return from {@link #getNextAnimationInChain} if the animation should not be
          * chained at all.
@@ -98,7 +130,7 @@
          * by getChildAt() and getChildCount().
          *
          * The controller can perform animations on the child (either manually, or by using
-         * {@link #animateValueForChild}), and then call finishRemoval when complete.
+         * {@link #animationForChild(View)}), and then call finishRemoval when complete.
          *
          * finishRemoval must be called by implementations of this method, or transient views will
          * never be removed.
@@ -125,14 +157,74 @@
         protected void setChildVisibility(View child, int index, int visibility) {
             child.setVisibility(visibility);
         }
+
+        /**
+         * Returns a {@link PhysicsPropertyAnimator} instance for the given child view.
+         */
+        protected PhysicsPropertyAnimator animationForChild(View child) {
+            PhysicsPropertyAnimator animator =
+                    (PhysicsPropertyAnimator) child.getTag(R.id.physics_animator_tag);
+
+            if (animator == null) {
+                animator = mLayout.new PhysicsPropertyAnimator(child);
+                child.setTag(R.id.physics_animator_tag, animator);
+            }
+
+            return animator;
+        }
+
+        /** Returns a {@link PhysicsPropertyAnimator} instance for child at the given index. */
+        protected PhysicsPropertyAnimator animationForChildAtIndex(int index) {
+            return animationForChild(mLayout.getChildAt(index));
+        }
+
+        /**
+         * Returns a {@link MultiAnimationStarter} whose startAll method will start the physics
+         * animations for all children from startIndex onward. The provided configurator will be
+         * called with each child's {@link PhysicsPropertyAnimator}, where it can set up each
+         * animation appropriately.
+         */
+        protected MultiAnimationStarter animationsForChildrenFromIndex(
+                int startIndex, ChildAnimationConfigurator configurator) {
+            final Set<DynamicAnimation.ViewProperty> allAnimatedProperties = new HashSet<>();
+            final List<PhysicsPropertyAnimator> allChildAnims = new ArrayList<>();
+
+            // Retrieve the animator for each child, ask the configurator to configure it, then save
+            // it and the properties it chose to animate.
+            for (int i = startIndex; i < mLayout.getChildCount(); i++) {
+                final PhysicsPropertyAnimator anim = animationForChildAtIndex(i);
+                configurator.configureAnimationForChildAtIndex(i, anim);
+                allAnimatedProperties.addAll(anim.getAnimatedProperties());
+                allChildAnims.add(anim);
+            }
+
+            // Return a MultiAnimationStarter that will start all of the child animations, and also
+            // add a multiple property end listener to the layout that will call the end action
+            // provided to startAll() once all animations on the animated properties complete.
+            return (endActions) -> {
+                if (endActions != null) {
+                    mLayout.setEndActionForMultipleProperties(
+                            () -> {
+                                for (Runnable action : endActions) {
+                                    action.run();
+                                }
+                            },
+                            allAnimatedProperties.toArray(
+                                    new DynamicAnimation.ViewProperty[0]));
+                }
+
+                for (PhysicsPropertyAnimator childAnim : allChildAnims) {
+                    childAnim.start();
+                }
+            };
+        }
     }
 
     /**
-     * End listeners that are called when every child's animation of the given property has
-     * finished.
+     * End actions that are called when every child's animation of the given property has finished.
      */
-    protected final HashMap<DynamicAnimation.ViewProperty, DynamicAnimation.OnAnimationEndListener>
-            mEndListenerForProperty = new HashMap<>();
+    protected final HashMap<DynamicAnimation.ViewProperty, Runnable> mEndActionForProperty =
+            new HashMap<>();
 
     /** Set of currently rendered transient views. */
     private final Set<View> mTransientViews = new HashSet<>();
@@ -165,7 +257,7 @@
      */
     public void setController(PhysicsAnimationController controller) {
         cancelAllAnimations();
-        mEndListenerForProperty.clear();
+        mEndActionForProperty.clear();
 
         this.mController = controller;
         mController.setLayout(this);
@@ -177,26 +269,27 @@
     }
 
     /**
-     * Sets an end listener that will be called when all child animations for a given property have
+     * Sets an end action that will be run when all child animations for a given property have
      * stopped running.
      */
-    public void setEndListenerForProperty(
-            DynamicAnimation.OnAnimationEndListener listener,
-            DynamicAnimation.ViewProperty property) {
-        mEndListenerForProperty.put(property, listener);
+    public void setEndActionForProperty(Runnable action, DynamicAnimation.ViewProperty property) {
+        mEndActionForProperty.put(property, action);
     }
 
     /**
-     * Sets an end listener that will be called whenever any of the given properties' animations
-     * end. For example, setting a listener for TRANSLATION_X and TRANSLATION_Y will result in that
-     * listener being called twice - once when all TRANSLATION_X animations end, and again when all
-     * TRANSLATION_Y animations end.
+     * Sets an end action that will be run when all child animations for all of the given properties
+     * have stopped running.
      */
-    public void setEndListenerForProperties(
-            DynamicAnimation.OnAnimationEndListener endListener,
-            DynamicAnimation.ViewProperty... properties) {
+    public void setEndActionForMultipleProperties(
+            Runnable action, DynamicAnimation.ViewProperty... properties) {
+        final Runnable checkIfAllFinished = () -> {
+            if (!arePropertiesAnimating(properties)) {
+                action.run();
+            }
+        };
+
         for (DynamicAnimation.ViewProperty property : properties) {
-            setEndListenerForProperty(endListener, property);
+            setEndActionForProperty(checkIfAllFinished, property);
         }
     }
 
@@ -204,8 +297,8 @@
      * Removes the end listener that would have been called when all child animations for a given
      * property stopped running.
      */
-    public void removeEndListenerForProperty(DynamicAnimation.ViewProperty property) {
-        mEndListenerForProperty.remove(property);
+    public void removeEndActionForProperty(DynamicAnimation.ViewProperty property) {
+        mEndActionForProperty.remove(property);
     }
 
     @Override
@@ -231,6 +324,11 @@
     }
 
     @Override
+    public void removeViewAt(int index) {
+        removeView(getChildAt(index));
+    }
+
+    @Override
     public void addTransientView(View view, int index) {
         super.addTransientView(view, index);
         mTransientViews.add(view);
@@ -304,7 +402,10 @@
 
         for (int i = 0; i < getChildCount(); i++) {
             for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
-                getAnimationAtIndex(property, i).cancel();
+                final DynamicAnimation anim = getAnimationAtIndex(property, i);
+                if (anim != null) {
+                    anim.cancel();
+                }
             }
         }
     }
@@ -316,107 +417,6 @@
         }
     }
 
-    /**
-     * Animates the property of the given child view, then runs the callback provided when the
-     * animation ends.
-     */
-    protected void animateValueForChild(
-            DynamicAnimation.ViewProperty property,
-            View view,
-            float value,
-            float startVel,
-            Runnable after) {
-        if (view != null) {
-            final SpringAnimation animation =
-                    (SpringAnimation) view.getTag(getTagIdForProperty(property));
-            if (after != null) {
-                animation.addEndListener(new OneTimeEndListener() {
-                    @Override
-                    public void onAnimationEnd(DynamicAnimation animation, boolean canceled,
-                            float value, float velocity) {
-                        super.onAnimationEnd(animation, canceled, value, velocity);
-                        after.run();
-                    }
-                });
-            }
-
-            // Set the start velocity if it's something other than the not-set value.
-            if (startVel != Float.MAX_VALUE) {
-                animation.setStartVelocity(startVel);
-            }
-
-            animation.animateToFinalPosition(value);
-        }
-    }
-
-    protected void animateValueForChild(
-            DynamicAnimation.ViewProperty property,
-            View view,
-            float value,
-            Runnable after) {
-        animateValueForChild(property, view, value, Float.MAX_VALUE, after);
-    }
-
-    protected void animateValueForChild(
-            DynamicAnimation.ViewProperty property,
-            View view,
-            float value) {
-        animateValueForChild(property, view, value, Float.MAX_VALUE, /* after */ null);
-    }
-
-    protected void animateValueForChild(
-            DynamicAnimation.ViewProperty property,
-            View view,
-            float value,
-            float startVel) {
-        animateValueForChild(property, view, value, startVel, /* after */ null);
-    }
-
-    /**
-     * Animates the property of the child at the given index to the given value, then runs the
-     * callback provided when the animation ends.
-     */
-    protected void animateValueForChildAtIndex(
-            DynamicAnimation.ViewProperty property,
-            int index,
-            float value,
-            float startVel,
-            Runnable after) {
-        animateValueForChild(property, getChildAt(index), value, startVel, after);
-    }
-
-    /** Shortcut to animate a value with a callback, but no start velocity. */
-    protected void animateValueForChildAtIndex(
-            DynamicAnimation.ViewProperty property,
-            int index,
-            float value,
-            Runnable after) {
-        animateValueForChildAtIndex(property, index, value, Float.MAX_VALUE, after);
-    }
-
-    /** Shortcut to animate a value with a start velocity, but no callback. */
-    protected void animateValueForChildAtIndex(
-            DynamicAnimation.ViewProperty property,
-            int index,
-            float value,
-            float startVel) {
-        animateValueForChildAtIndex(property, index, value, startVel, /* callback */ null);
-    }
-
-    /** Shortcut to animate a value without changing the velocity or providing a callback. */
-    protected void animateValueForChildAtIndex(
-            DynamicAnimation.ViewProperty property,
-            int index,
-            float value) {
-        animateValueForChildAtIndex(property, index, value, Float.MAX_VALUE, /* callback */ null);
-    }
-
-    /** Shortcut to animate a child view's TRANSLATION_X and TRANSLATION_Y values. */
-    protected void animatePositionForChildAtIndex(int index, float x, float y) {
-        animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_X, index, x);
-        animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_Y, index, y);
-    }
-
     /** Whether the first child would be left of center if translated to the given x value. */
     protected boolean isFirstChildXLeftOfCenter(float x) {
         if (getChildCount() > 0) {
@@ -562,40 +562,256 @@
         public void onAnimationEnd(
                 DynamicAnimation anim, boolean canceled, float value, float velocity) {
             if (!arePropertiesAnimating(mProperty)) {
-                if (mEndListenerForProperty.containsKey(mProperty)) {
-                    mEndListenerForProperty.get(mProperty).onAnimationEnd(anim, canceled, value,
-                            velocity);
+                if (mEndActionForProperty.containsKey(mProperty)) {
+                    mEndActionForProperty.get(mProperty).run();
                 }
             }
         }
     }
 
     /**
-     * One time end listener that waits for every animation on every given property to finish. At
-     * that point, it calls {@link #onAllAnimationsForPropertiesEnd} and then removes itself as an
-     * end listener from each property.
+     * Animator class returned by {@link PhysicsAnimationController#animationForChild}, to allow
+     * controllers to animate child views using physics animations.
+     *
+     * See docs/physics-animation-layout.md for documentation and examples.
      */
-    public abstract class OneTimeMultiplePropertyEndListener
-            implements DynamicAnimation.OnAnimationEndListener {
-        final DynamicAnimation.ViewProperty[] mViewProperties;
+    protected class PhysicsPropertyAnimator {
+        /** The view whose properties this animator animates. */
+        private View mView;
 
-        OneTimeMultiplePropertyEndListener(DynamicAnimation.ViewProperty... properties) {
-            mViewProperties = properties;
+        /** Start velocity to use for all property animations. */
+        private float mDefaultStartVelocity = 0f;
+
+        /** Start delay to use when start is called. */
+        private long mStartDelay = 0;
+
+        /** End actions to call when animations for the given property complete. */
+        private Map<DynamicAnimation.ViewProperty, Runnable[]> mEndActionsForProperty =
+                new HashMap<>();
+
+        /**
+         * Start velocities to use for TRANSLATION_X and TRANSLATION_Y, since these are often
+         * provided by VelocityTrackers and differ from each other.
+         */
+        private Map<DynamicAnimation.ViewProperty, Float> mPositionStartVelocities =
+                new HashMap<>();
+
+        /**
+         * End actions to call when both TRANSLATION_X and TRANSLATION_Y animations have completed,
+         * if {@link #position} was used to animate TRANSLATION_X and TRANSLATION_Y simultaneously.
+         */
+        private Runnable[] mPositionEndActions;
+
+        /**
+         * All of the properties that have been set and will animate when {@link #start} is called.
+         */
+        private Map<DynamicAnimation.ViewProperty, Float> mAnimatedProperties = new HashMap<>();
+
+        protected PhysicsPropertyAnimator(View view) {
+            this.mView = view;
         }
 
-        @Override
-        public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
-                float velocity) {
-            if (!arePropertiesAnimating(mViewProperties)) {
-                onAllAnimationsForPropertiesEnd();
+        /** Animate a property to the given value, then call the optional end actions. */
+        public PhysicsPropertyAnimator property(
+                DynamicAnimation.ViewProperty property, float value, Runnable... endActions) {
+            mAnimatedProperties.put(property, value);
+            mEndActionsForProperty.put(property, endActions);
+            return this;
+        }
 
-                for (DynamicAnimation.ViewProperty property : mViewProperties) {
-                    removeEndListenerForProperty(property);
+        /** Animate the view's alpha value to the provided value. */
+        public PhysicsPropertyAnimator alpha(float alpha, Runnable... endActions) {
+            return property(DynamicAnimation.ALPHA, alpha, endActions);
+        }
+
+        /** Set the view's alpha value to 'from', then animate it to the given value. */
+        public PhysicsPropertyAnimator alpha(float from, float to, Runnable... endActions) {
+            mView.setAlpha(from);
+            return alpha(to, endActions);
+        }
+
+        /** Animate the view's translationX value to the provided value. */
+        public PhysicsPropertyAnimator translationX(float translationX, Runnable... endActions) {
+            return property(DynamicAnimation.TRANSLATION_X, translationX, endActions);
+        }
+
+        /** Set the view's translationX value to 'from', then animate it to the given value. */
+        public PhysicsPropertyAnimator translationX(
+                float from, float to, Runnable... endActions) {
+            mView.setTranslationX(from);
+            return translationX(to, endActions);
+        }
+
+        /** Animate the view's translationY value to the provided value. */
+        public PhysicsPropertyAnimator translationY(float translationY, Runnable... endActions) {
+            return property(DynamicAnimation.TRANSLATION_Y, translationY, endActions);
+        }
+
+        /** Set the view's translationY value to 'from', then animate it to the given value. */
+        public PhysicsPropertyAnimator translationY(
+                float from, float to, Runnable... endActions) {
+            mView.setTranslationY(from);
+            return translationY(to, endActions);
+        }
+
+        /**
+         * Animate the view's translationX and translationY values, and call the end actions only
+         * once both TRANSLATION_X and TRANSLATION_Y animations have completed.
+         */
+        public PhysicsPropertyAnimator position(
+                float translationX, float translationY, Runnable... endActions) {
+            mPositionEndActions = endActions;
+            translationX(translationX);
+            return translationY(translationY);
+        }
+
+        /** Animate the view's scaleX value to the provided value. */
+        public PhysicsPropertyAnimator scaleX(float scaleX, Runnable... endActions) {
+            return property(DynamicAnimation.SCALE_X, scaleX, endActions);
+        }
+
+        /** Set the view's scaleX value to 'from', then animate it to the given value. */
+        public PhysicsPropertyAnimator scaleX(float from, float to, Runnable... endActions) {
+            mView.setScaleX(from);
+            return scaleX(to, endActions);
+        }
+
+        /** Animate the view's scaleY value to the provided value. */
+        public PhysicsPropertyAnimator scaleY(float scaleY, Runnable... endActions) {
+            return property(DynamicAnimation.SCALE_Y, scaleY, endActions);
+        }
+
+        /** Set the view's scaleY value to 'from', then animate it to the given value. */
+        public PhysicsPropertyAnimator scaleY(float from, float to, Runnable... endActions) {
+            mView.setScaleY(from);
+            return scaleY(to, endActions);
+        }
+
+        /** Set the start velocity to use for all property animations. */
+        public PhysicsPropertyAnimator withStartVelocity(float startVel) {
+            mDefaultStartVelocity = startVel;
+            return this;
+        }
+
+        /**
+         * Set the start velocities to use for TRANSLATION_X and TRANSLATION_Y animations. This
+         * overrides any value set via {@link #withStartVelocity(float)} for those properties.
+         */
+        public PhysicsPropertyAnimator withPositionStartVelocities(float velX, float velY) {
+            mPositionStartVelocities.put(DynamicAnimation.TRANSLATION_X, velX);
+            mPositionStartVelocities.put(DynamicAnimation.TRANSLATION_Y, velY);
+            return this;
+        }
+
+        /** Set a delay, in milliseconds, before kicking off the animations. */
+        public PhysicsPropertyAnimator withStartDelay(long startDelay) {
+            mStartDelay = startDelay;
+            return this;
+        }
+
+        /**
+         * Start the animations, and call the optional end actions once all animations for every
+         * animated property on every child (including chained animations) have ended.
+         */
+        public void start(Runnable... after) {
+            final Set<DynamicAnimation.ViewProperty> properties = getAnimatedProperties();
+
+            // If there are end actions, set an end listener on the layout for all the properties
+            // we're about to animate.
+            if (after != null) {
+                final DynamicAnimation.ViewProperty[] propertiesArray =
+                        properties.toArray(new DynamicAnimation.ViewProperty[0]);
+                for (Runnable callback : after) {
+                    setEndActionForMultipleProperties(callback, propertiesArray);
+                }
+            }
+
+            // If we used position-specific end actions, we'll need to listen for both TRANSLATION_X
+            // and TRANSLATION_Y animations ending, and call them once both have finished.
+            if (mPositionEndActions != null) {
+                final SpringAnimation translationXAnim =
+                        getAnimationFromView(DynamicAnimation.TRANSLATION_X, mView);
+                final SpringAnimation translationYAnim =
+                        getAnimationFromView(DynamicAnimation.TRANSLATION_Y, mView);
+                final Runnable waitForBothXAndY = () -> {
+                    if (!translationXAnim.isRunning() && !translationYAnim.isRunning()) {
+                        if (mPositionEndActions != null) {
+                            for (Runnable callback : mPositionEndActions) {
+                                callback.run();
+                            }
+                        }
+
+                        mPositionEndActions = null;
+                    }
+                };
+
+                mEndActionsForProperty.put(DynamicAnimation.TRANSLATION_X,
+                        new Runnable[]{waitForBothXAndY});
+                mEndActionsForProperty.put(DynamicAnimation.TRANSLATION_Y,
+                        new Runnable[]{waitForBothXAndY});
+            }
+
+            // Actually start the animations.
+            for (DynamicAnimation.ViewProperty property : properties) {
+                animateValueForChild(
+                        property,
+                        mView,
+                        mAnimatedProperties.get(property),
+                        mPositionStartVelocities.getOrDefault(property, mDefaultStartVelocity),
+                        mStartDelay,
+                        mEndActionsForProperty.get(property));
+            }
+
+            // Clear out the animator.
+            mAnimatedProperties.clear();
+            mPositionStartVelocities.clear();
+            mDefaultStartVelocity = 0;
+            mStartDelay = 0;
+            mEndActionsForProperty.clear();
+        }
+
+        /** Returns the set of properties that will animate once {@link #start} is called. */
+        protected Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
+            return mAnimatedProperties.keySet();
+        }
+
+        /**
+         * Animates the property of the given child view, then runs the callback provided when the
+         * animation ends.
+         */
+        protected void animateValueForChild(
+                DynamicAnimation.ViewProperty property,
+                View view,
+                float value,
+                float startVel,
+                long startDelay,
+                Runnable[] afterCallbacks) {
+            if (view != null) {
+                final SpringAnimation animation =
+                        (SpringAnimation) view.getTag(getTagIdForProperty(property));
+                if (afterCallbacks != null) {
+                    animation.addEndListener(new OneTimeEndListener() {
+                        @Override
+                        public void onAnimationEnd(DynamicAnimation animation, boolean canceled,
+                                float value, float velocity) {
+                            super.onAnimationEnd(animation, canceled, value, velocity);
+                            for (Runnable runnable : afterCallbacks) {
+                                runnable.run();
+                            }
+                        }
+                    });
+                }
+
+                if (startVel > 0) {
+                    animation.setStartVelocity(startVel);
+                }
+
+                if (startDelay > 0) {
+                    postDelayed(() -> animation.animateToFinalPosition(value), startDelay);
+                } else {
+                    animation.animateToFinalPosition(value);
                 }
             }
         }
-
-        /** Called when every animation for every property has finished. */
-        abstract void onAllAnimationsForPropertiesEnd();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 3c4bc72..c395031 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -206,12 +206,12 @@
                         .setDampingRatio(SPRING_DAMPING_RATIO),
                 /* destination */ null);
 
-        mLayout.setEndListenerForProperties(
-                (animation, canceled, value, velocity) -> {
+        mLayout.setEndActionForMultipleProperties(
+                () -> {
                     mRestingStackPosition = new PointF();
                     mRestingStackPosition.set(mStackPosition);
-                    mLayout.removeEndListenerForProperty(DynamicAnimation.TRANSLATION_X);
-                    mLayout.removeEndListenerForProperty(DynamicAnimation.TRANSLATION_Y);
+                    mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_X);
+                    mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_Y);
                 },
                 DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
     }
@@ -292,8 +292,8 @@
         cancelStackPositionAnimation(DynamicAnimation.TRANSLATION_X);
         cancelStackPositionAnimation(DynamicAnimation.TRANSLATION_Y);
 
-        mLayout.removeEndListenerForProperty(DynamicAnimation.TRANSLATION_X);
-        mLayout.removeEndListenerForProperty(DynamicAnimation.TRANSLATION_Y);
+        mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_X);
+        mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_Y);
     }
 
     /**
@@ -441,19 +441,18 @@
 
     @Override
     void onChildRemoved(View child, int index, Runnable finishRemoval) {
-        // Animate the child out, actually removing it once its alpha is zero.
-        mLayout.animateValueForChild(DynamicAnimation.ALPHA, child, 0f, finishRemoval);
-        mLayout.animateValueForChild(DynamicAnimation.SCALE_X, child, ANIMATE_IN_STARTING_SCALE);
-        mLayout.animateValueForChild(DynamicAnimation.SCALE_Y, child, ANIMATE_IN_STARTING_SCALE);
-
         // Animate the removing view in the opposite direction of the stack.
         final float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
-        mLayout.animateValueForChild(DynamicAnimation.TRANSLATION_X, child,
-                mStackPosition.x - (-xOffset * ANIMATE_TRANSLATION_FACTOR));
+        animationForChild(child)
+                .alpha(0f, finishRemoval /* after */)
+                .scaleX(ANIMATE_IN_STARTING_SCALE)
+                .scaleY(ANIMATE_IN_STARTING_SCALE)
+                .translationX(mStackPosition.x - (-xOffset * ANIMATE_TRANSLATION_FACTOR))
+                .start();
 
-        // Pull the top of the stack to the correct position, the chained animations will instruct
-        // any children that are out of place to animate to the correct position.
-        mLayout.animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_X, 0, mStackPosition.x);
+        if (mLayout.getChildCount() > 0) {
+            animationForChildAtIndex(0).translationX(mStackPosition.x).start();
+        }
     }
 
     /** Moves the stack, without any animation, to the starting position. */
@@ -486,10 +485,12 @@
 
         if (mLayout.getChildCount() > 0) {
             property.setValue(mLayout.getChildAt(0), value);
-            mLayout.animateValueForChildAtIndex(
-                    property,
-                    /* index */ 1,
-                    value + getOffsetForChainedPropertyAnimation(property));
+
+            if (mLayout.getChildCount() > 1) {
+                animationForChildAtIndex(1)
+                        .property(property, value + getOffsetForChainedPropertyAnimation(property))
+                        .start();
+            }
         }
     }
 
@@ -520,23 +521,15 @@
     private void animateInBubble(View child) {
         child.setTranslationY(mStackPosition.y);
 
-        // Pop in the new bubble.
-        child.setScaleX(ANIMATE_IN_STARTING_SCALE);
-        child.setScaleY(ANIMATE_IN_STARTING_SCALE);
-        mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_X, 0, 1f);
-        mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_Y, 0, 1f);
-
-        // Fade in the new bubble.
-        child.setAlpha(0);
-        mLayout.animateValueForChildAtIndex(DynamicAnimation.ALPHA, 0, 1f);
-
-        // Start the new bubble 4x the normal offset distance in the opposite direction. We'll
-        // animate in from this position. Since the animations are chained, when the new bubble
-        // flies in from the side, it will push the other ones out of the way.
         float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
-        child.setTranslationX(mStackPosition.x - ANIMATE_TRANSLATION_FACTOR * xOffset);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X, 0, mStackPosition.x);
+        animationForChild(child)
+                .scaleX(ANIMATE_IN_STARTING_SCALE /* from */, 1f /* to */)
+                .scaleY(ANIMATE_IN_STARTING_SCALE /* from */, 1f /* to */)
+                .alpha(0f /* from */, 1f /* to */)
+                .translationX(
+                        mStackPosition.x - ANIMATE_TRANSLATION_FACTOR * xOffset /* from */,
+                        mStackPosition.x /* to */)
+                .start();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 6c4be06..c243899 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -211,7 +211,7 @@
         mDozeService.requestWakeUp();
     }
 
-    private boolean isExecutingTransition() {
+    public boolean isExecutingTransition() {
         return !mQueuedRequests.isEmpty();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 031f562..7189a48 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -198,6 +198,14 @@
     }
 
     private void onProximityFar(boolean far) {
+        // Proximity checks are asynchronous and the user might have interacted with the phone
+        // when a new event is arriving. This means that a state transition might have happened
+        // and the proximity check is now obsolete.
+        if (mMachine.isExecutingTransition()) {
+            Log.w(TAG, "onProximityFar called during transition. Ignoring sensor response.");
+            return;
+        }
+
         final boolean near = !far;
         final DozeMachine.State state = mMachine.getState();
         final boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
index 477e7d7e..d1939d0 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
@@ -85,7 +85,9 @@
             Bitmap bitmap = bitmaps[0];
             if (bitmap != null) {
                 int[] histogram = processHistogram(bitmap);
-                return computePercentile85(bitmap, histogram);
+                Float val = computePercentile85(bitmap, histogram);
+                bitmaps[0] = null;
+                return val;
             }
             Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
             return DEFAULT_PER85;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 676e594..d70d0d8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -90,6 +90,7 @@
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -710,7 +711,10 @@
         mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
                 SYSTEMUI_PERMISSION, null /* scheduler */);
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
+        InjectionInflationController injectionInflationController =
+                new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent());
+        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext,
+                injectionInflationController);
 
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 9f0f53e..3a0534d2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -38,8 +38,10 @@
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
 import android.util.Log;
+import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -133,9 +135,12 @@
 
         String dialogTitle = getString(R.string.media_projection_dialog_title, appName);
 
+        View dialogTitleView = View.inflate(this, R.layout.media_projection_dialog_title, null);
+        TextView titleText = (TextView) dialogTitleView.findViewById(R.id.dialog_title);
+        titleText.setText(dialogTitle);
+
         mDialog = new AlertDialog.Builder(this)
-                .setTitle(dialogTitle)
-                .setIcon(R.drawable.ic_media_projection_permission)
+                .setCustomTitle(dialogTitleView)
                 .setMessage(message)
                 .setPositiveButton(R.string.media_projection_action_text, this)
                 .setNegativeButton(android.R.string.cancel, this)
diff --git a/packages/SystemUI/src/com/android/systemui/media/OWNERS b/packages/SystemUI/src/com/android/systemui/media/OWNERS
new file mode 100644
index 0000000..69ea57b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/OWNERS
@@ -0,0 +1 @@
+per-file MediaProjectionPermissionActivity.java = michaelwr@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 0ae8f6c..10eacba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -87,7 +87,6 @@
 
     private boolean mListening;
 
-    private View mDivider;
     protected MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
 
@@ -133,7 +132,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mDivider = findViewById(R.id.qs_footer_divider);
         mEdit = findViewById(android.R.id.edit);
         mEdit.setOnClickListener(view ->
                 mActivityStarter.postQSRunnableDismissingKeyguard(() ->
@@ -218,7 +216,6 @@
     @Nullable
     private TouchAnimator createFooterAnimator() {
         return new TouchAnimator.Builder()
-                .addFloat(mDivider, "alpha", 0, 1)
                 .addFloat(mActionsContainer, "alpha", 0, 1)
                 .addFloat(mEditContainer, "alpha", 0, 1)
                 .addFloat(mDragHandle, "alpha", 1, 0, 0)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index c897b9c..d789821 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -395,14 +395,13 @@
 
     private void updateStatusIconAlphaAnimator() {
         mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
-                .addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
+                .addFloat(mQuickQsStatusIcons, "alpha", 1, 0, 0)
                 .build();
     }
 
     private void updateHeaderTextContainerAlphaAnimator() {
         mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
-                .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
-                .setStartDelay(.5f)
+                .addFloat(mHeaderTextContainerView, "alpha", 0, 0, 1)
                 .build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 813faa9..520df97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -36,6 +36,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PointF;
 import android.graphics.PorterDuff;
@@ -58,6 +59,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
@@ -394,6 +396,16 @@
             }
         }
     };
+    private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
+        @Override
+        public void getOutline(View view, Outline outline) {
+            if (mAmbientState.isDarkAtAll() && !mAmbientState.isFullyDark()) {
+                outline.setRoundRect(mBackgroundAnimationRect, mCornerRadius);
+            } else {
+                ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
+            }
+        }
+    };
     private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
     private boolean mPulsing;
     private boolean mGroupExpandedForMeasure;
@@ -520,6 +532,7 @@
         mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
         mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
         addOnExpandedHeightListener(mRoundnessManager::setExpanded);
+        setOutlineProvider(mOutlineProvider);
 
         // Blocking helper manager wants to know the expanded state, update as well.
         NotificationBlockingHelperManager blockingHelperManager =
@@ -1298,6 +1311,7 @@
     public void updateClipping() {
         boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
                 && !mHeadsUpAnimatingAway;
+        boolean clipToOutline = false;
         if (mIsClipped != clipped) {
             mIsClipped = clipped;
         }
@@ -1306,12 +1320,15 @@
                 && mAmbientState.isFullyDark() && mShowDarkShelf) {
             setClipBounds(null);
         } else if (mAmbientState.isDarkAtAll()) {
-            setClipBounds(mBackgroundAnimationRect);
+            clipToOutline = true;
+            invalidateOutline();
         } else if (clipped) {
             setClipBounds(mRequestedClipBounds);
         } else {
             setClipBounds(null);
         }
+
+        setClipToOutline(clipToOutline);
     }
 
     /**
@@ -4805,6 +4822,9 @@
         if (!wasDarkAtAll && nowDarkAtAll) {
             resetExposedMenuView(true /* animate */, true /* animate */);
         }
+        if (nowFullyDark != wasFullyDark || wasDarkAtAll != nowDarkAtAll) {
+            invalidateOutline();
+        }
         updateAlgorithmHeightAndPadding();
         updateBackgroundDimming();
         updatePanelTranslation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 5a7df1f..ca45209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricSourceType;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -26,6 +27,8 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -140,6 +143,8 @@
         }
     };
 
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+
     public BiometricUnlockController(Context context,
             DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator,
@@ -253,6 +258,8 @@
             Trace.endSection();
             return;
         }
+        mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
+                .setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
         startWakeAndUnlock(calculateMode(biometricSourceType));
     }
 
@@ -420,12 +427,16 @@
 
     @Override
     public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
+        mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
+                .setType(MetricsEvent.TYPE_FAILURE).setSubtype(toSubtype(biometricSourceType)));
         cleanup();
     }
 
     @Override
     public void onBiometricError(int msgId, String errString,
             BiometricSourceType biometricSourceType) {
+        mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
+                .setType(MetricsEvent.TYPE_ERROR).setSubtype(toSubtype(biometricSourceType)));
         cleanup();
     }
 
@@ -501,4 +512,20 @@
     public boolean isBiometricUnlock() {
         return isWakeAndUnlock() || mMode == MODE_UNLOCK;
     }
+
+    /**
+     * Translates biometric source type for logging purpose.
+     */
+    private int toSubtype(BiometricSourceType biometricSourceType) {
+        switch (biometricSourceType) {
+            case FINGERPRINT:
+                return 0;
+            case FACE:
+                return 1;
+            case IRIS:
+                return 2;
+            default:
+                return 3;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index c8ce392..4c50d07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -468,6 +468,11 @@
     }
 
     @Override
+    public void onDensityOrFontScaleChanged() {
+        loadDimens();
+    }
+
+    @Override
     public void onOverlayChanged() {
         mCarrierLabel.setTextAppearance(
                 Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
@@ -514,6 +519,8 @@
             return;
         }
         mDozing = dozing;
+        setClipChildren(!dozing);
+        setClipToPadding(!dozing);
         updateVisibilities();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 18612c3..e9a9606 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -50,8 +50,6 @@
 import android.graphics.Region;
 import android.graphics.Region.Op;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
@@ -150,10 +148,6 @@
     private final NavigationBarTransitions mBarTransitions;
     private final OverviewProxyService mOverviewProxyService;
 
-    // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
-    final static boolean WORKAROUND_INVALID_LAYOUT = true;
-    final static int MSG_CHECK_INVALID_LAYOUT = 8686;
-
     // performs manual animation in sync with layout transitions
     private final NavTransitionListener mTransitionListener = new NavTransitionListener();
 
@@ -182,7 +176,6 @@
     private NavigationBackAction mBackAction;
     private QuickSwitchAction mQuickSwitchAction;
     private NavigationAssistantAction mAssistantAction;
-    private NavigationNotificationPanelAction mNotificationPanelAction;
 
     private NavigationBarEdgePanel mLeftEdgePanel;
     private NavigationBarEdgePanel mRightEdgePanel;
@@ -261,29 +254,6 @@
         }
     };
 
-    private class H extends Handler {
-        public void handleMessage(Message m) {
-            switch (m.what) {
-                case MSG_CHECK_INVALID_LAYOUT:
-                    final String how = "" + m.obj;
-                    final int w = getWidth();
-                    final int h = getHeight();
-                    final int vw = getCurrentView().getWidth();
-                    final int vh = getCurrentView().getHeight();
-
-                    if (h != vh || w != vw) {
-                        Log.w(TAG, String.format(
-                            "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
-                            how, w, h, vw, vh));
-                        if (WORKAROUND_INVALID_LAYOUT) {
-                            requestLayout();
-                        }
-                    }
-                    break;
-            }
-        }
-    }
-
     private final AccessibilityDelegate mQuickStepAccessibilityDelegate
             = new AccessibilityDelegate() {
         private AccessibilityAction mToggleOverviewAction;
@@ -451,7 +421,7 @@
                 mQuickScrubAction, null /* swipeLeftEdgeAction */, null /* swipeRightEdgeAction */
         };
 
-        mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
+        mPrototypeController = new NavigationPrototypeController(mContext);
         mPrototypeController.register();
         mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
         mColorAdaptionController = new NavBarTintController(this, getLightTransitionsController());
@@ -475,10 +445,6 @@
             mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
                     assistManager);
         }
-        if (mNotificationPanelAction == null) {
-            mNotificationPanelAction = new NavigationNotificationPanelAction(this,
-                    mOverviewProxyService, panel);
-        }
         if (mGestureHelper instanceof QuickStepController) {
             ((QuickStepController) mGestureHelper).setComponents(this);
             updateNavigationGestures();
@@ -517,8 +483,6 @@
                 return mQuickSwitchAction;
             case NavigationPrototypeController.ACTION_ASSISTANT:
                 return mAssistantAction;
-            case NavigationPrototypeController.ACTION_EXPAND_NOTIFICATION:
-                return mNotificationPanelAction;
             case NavigationPrototypeController.ACTION_NOTHING:
                 return null;
             default:
@@ -598,8 +562,6 @@
         getHomeButton().abortCurrentGesture();
     }
 
-    private H mHandler = new H();
-
     public View getCurrentView() {
         return mCurrentView;
     }
@@ -1200,23 +1162,23 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int w = MeasureSpec.getSize(widthMeasureSpec);
+        int h = MeasureSpec.getSize(heightMeasureSpec);
         if (DEBUG) Log.d(TAG, String.format(
-                    "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
+                "onMeasure: (%dx%d) old: (%dx%d)", w, h, getMeasuredWidth(), getMeasuredHeight()));
 
         final boolean newVertical = w > 0 && h > w;
         if (newVertical != mIsVertical) {
             mIsVertical = newVertical;
             if (DEBUG) {
-                Log.d(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w,
+                Log.d(TAG, String.format("onMeasure: h=%d, w=%d, vert=%s", h, w,
                         mIsVertical ? "y" : "n"));
             }
             reorient();
             notifyVerticalChangedListener(newVertical);
         }
-
-        postCheckForInvalidLayout("sizeChanged");
-        super.onSizeChanged(w, h, oldw, oldh);
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
     private void notifyVerticalChangedListener(boolean newVertical) {
@@ -1271,28 +1233,6 @@
         return uiCarModeChanged;
     }
 
-    /*
-    @Override
-    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
-        if (DEBUG) Log.d(TAG, String.format(
-                    "onLayout: %s (%d,%d,%d,%d)",
-                    changed?"changed":"notchanged", left, top, right, bottom));
-        super.onLayout(changed, left, top, right, bottom);
-    }
-
-    // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
-    // fails, any touch on the display will fix the layout.
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            postCheckForInvalidLayout("touch");
-        }
-        return super.onInterceptTouchEvent(ev);
-    }
-    */
-
-
     private String getResourceName(int resId) {
         if (resId != 0) {
             final android.content.res.Resources res = getContext().getResources();
@@ -1306,10 +1246,6 @@
         }
     }
 
-    private void postCheckForInvalidLayout(final String how) {
-        mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
-    }
-
     private static String visibilityToString(int vis) {
         switch (vis) {
             case View.INVISIBLE:
@@ -1478,7 +1414,7 @@
         void onVerticalChanged(boolean isVertical);
     }
 
-    private final Consumer<Boolean> mDockedListener = exists -> mHandler.post(() -> {
+    private final Consumer<Boolean> mDockedListener = exists -> post(() -> {
         mDockedStackExists = exists;
         updateRecentsIcon();
     });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java
deleted file mode 100644
index 6c7870d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.annotation.NonNull;
-import android.view.MotionEvent;
-
-import com.android.systemui.recents.OverviewProxyService;
-
-/**
- * Triggers notification panel to be expanded when executed
- */
-public class NavigationNotificationPanelAction extends NavigationGestureAction {
-    private final NotificationPanelView mPanelView;
-
-    public NavigationNotificationPanelAction(@NonNull NavigationBarView navigationBarView,
-            @NonNull OverviewProxyService service, @NonNull NotificationPanelView panelView) {
-        super(navigationBarView, service);
-        mPanelView = panelView;
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return true;
-    }
-
-    @Override
-    public boolean disableProxyEvents() {
-        return true;
-    }
-
-    @Override
-    public void onGestureStart(MotionEvent event) {
-        mPanelView.expand(true);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index 31579c2..9ea8b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -47,7 +47,7 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
-            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT, ACTION_EXPAND_NOTIFICATION})
+            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
     @interface GestureAction {}
     static final int ACTION_DEFAULT = 0;
     static final int ACTION_QUICKSTEP = 1;
@@ -56,7 +56,6 @@
     static final int ACTION_QUICKSWITCH = 4;
     static final int ACTION_NOTHING = 5;
     static final int ACTION_ASSISTANT = 6;
-    static final int ACTION_EXPAND_NOTIFICATION = 7;
 
     private OnPrototypeChangedListener mListener;
 
@@ -68,8 +67,8 @@
 
     private final Context mContext;
 
-    public NavigationPrototypeController(Handler handler, Context context) {
-        super(handler);
+    public NavigationPrototypeController(Context context) {
+        super(new Handler());
         mContext = context;
         updateSwipeLTRBackSetting();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 253bdfb..b902e43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -141,6 +142,7 @@
     private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties()
             .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
 
+    private final InjectionInflationController mInjectionInflationController;
     private final PowerManager mPowerManager;
     private final AccessibilityManager mAccessibilityManager;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -336,10 +338,12 @@
 
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
+            InjectionInflationController injectionInflationController,
             NotificationWakeUpCoordinator coordinator,
             PulseExpansionHandler pulseExpansionHandler) {
         super(context, attrs);
         setWillNotDraw(!DEBUG);
+        mInjectionInflationController = injectionInflationController;
         mFalsingManager = FalsingManager.getInstance(context);
         mPowerManager = context.getSystemService(PowerManager.class);
         mWakeUpCoordinator = coordinator;
@@ -475,10 +479,11 @@
         // Re-inflate the status view group.
         int index = indexOfChild(mKeyguardStatusView);
         removeView(mKeyguardStatusView);
-        mKeyguardStatusView = (KeyguardStatusView) LayoutInflater.from(mContext).inflate(
-                R.layout.keyguard_status_view,
-                this,
-                false);
+        mKeyguardStatusView = (KeyguardStatusView) mInjectionInflationController
+                .injectable(LayoutInflater.from(mContext)).inflate(
+                    R.layout.keyguard_status_view,
+                    this,
+                    false);
         addView(mKeyguardStatusView, index);
 
         // Re-associate the clock container with the keyguard clock switch.
@@ -490,10 +495,11 @@
         index = indexOfChild(mKeyguardBottomArea);
         removeView(mKeyguardBottomArea);
         KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
-        mKeyguardBottomArea = (KeyguardBottomAreaView) LayoutInflater.from(mContext).inflate(
-                R.layout.keyguard_bottom_area,
-                this,
-                false);
+        mKeyguardBottomArea = (KeyguardBottomAreaView) mInjectionInflationController
+                .injectable(LayoutInflater.from(mContext)).inflate(
+                    R.layout.keyguard_bottom_area,
+                    this,
+                    false);
         mKeyguardBottomArea.initFrom(oldBottomArea);
         addView(mKeyguardBottomArea, index);
         initBottomArea();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index a8ae5f6..9609057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -114,17 +114,19 @@
             if (mSingleTapEnabled) {
                 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
                         "SINGLE_TAP");
+                return true;
             }
-            return mSingleTapEnabled;
+            return false;
         }
 
         @Override
         public boolean onDoubleTap(MotionEvent e) {
-            if (mDoubleTapEnabled) {
+            if (mDoubleTapEnabled || mSingleTapEnabled) {
                 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
                         "DOUBLE_TAP");
+                return true;
             }
-            return mDoubleTapEnabled;
+            return false;
         }
     };
     private final TunerService.Tunable mTunable = (key, newValue) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 3c8ed6e..b53ff0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.Context;
 
+import com.android.internal.util.Preconditions;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -69,7 +71,8 @@
     }
 
     @Override
-    public void addCallback(Callback callback) {
+    public void addCallback(@NonNull Callback callback) {
+        Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
         mCallbacks.add(callback);
         if (mCallbacks.size() != 0 && !mListening) {
             mListening = true;
@@ -81,7 +84,8 @@
     }
 
     @Override
-    public void removeCallback(Callback callback) {
+    public void removeCallback(@NonNull Callback callback) {
+        Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
         if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) {
             mListening = false;
             mKeyguardUpdateMonitor.removeCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index e6b6672..7705e4e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -23,6 +23,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 
+import com.android.keyguard.KeyguardClockSwitch;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.qs.QSCarrierGroup;
 import com.android.systemui.qs.QSFooterImpl;
@@ -130,6 +131,11 @@
          * Creates the QSCarrierGroup
          */
         QSCarrierGroup createQSCarrierGroup();
+
+        /**
+         * Creates the KeyguardClockSwitch.
+         */
+        KeyguardClockSwitch createKeyguardClockSwitch();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
new file mode 100644
index 0000000..8ec66e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.R;
+
+/** Toggle button in Volume Dialog that allows extra state for when streams are opted-out */
+public class CaptionsToggleImageButton extends AlphaOptimizedImageButton {
+
+    private static final int[] OPTED_OUT_STATE = new int[] { R.attr.optedOut };
+
+    private boolean mComponentEnabled = false;
+    private boolean mOptedOut = false;
+
+    public CaptionsToggleImageButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(int extraSpace) {
+        int[] state = super.onCreateDrawableState(extraSpace + 1);
+        if (mOptedOut) {
+            mergeDrawableStates(state, OPTED_OUT_STATE);
+        }
+        return state;
+    }
+
+    Runnable setComponentEnabled(boolean isComponentEnabled) {
+        this.mComponentEnabled = isComponentEnabled;
+
+        return this.setImageResourceAsync(this.mComponentEnabled
+                ? R.drawable.ic_volume_odi_captions
+                : R.drawable.ic_volume_odi_captions_disabled);
+    }
+
+    boolean getComponentEnabled() {
+        return this.mComponentEnabled;
+    }
+
+    /** Sets whether or not the current stream has opted out of captions */
+    void setOptedOut(boolean isOptedOut) {
+        this.mOptedOut = isOptedOut;
+        refreshDrawableState();
+    }
+
+    boolean getOptedOut() {
+        return this.mOptedOut;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 2fa8889..a3db533 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -282,6 +282,13 @@
                 Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
     }
 
+    @Override
+    public boolean isCaptionStreamOptedOut() {
+        int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_OPTED_OUT, 0);
+        return currentValue == 1;
+    }
+
     public void getCaptionsComponentState(boolean fromTooltip) {
         if (mDestroyed) return;
         mWorker.obtainMessage(W.GET_CAPTIONS_COMPONENT_STATE, fromTooltip).sendToTarget();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index cdda216..bd7824d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -133,7 +133,7 @@
     private ViewGroup mRinger;
     private ImageButton mRingerIcon;
     private ViewGroup mODICaptionsView;
-    private ImageButton mODICaptionsIcon;
+    private CaptionsToggleImageButton mODICaptionsIcon;
     private View mSettingsView;
     private ImageButton mSettingsIcon;
     private FrameLayout mZenIcon;
@@ -587,11 +587,15 @@
     }
 
     private void updateCaptionsIcon() {
-        mHandler.post(
-                mODICaptionsIcon.setImageResourceAsync(
-                        mController.areCaptionsEnabled()
-                                ? R.drawable.ic_volume_odi_captions
-                                : R.drawable.ic_volume_odi_captions_disabled));
+        boolean componentEnabled = mController.areCaptionsEnabled();
+        if (mODICaptionsIcon.getComponentEnabled() != componentEnabled) {
+            mHandler.post(mODICaptionsIcon.setComponentEnabled(componentEnabled));
+        }
+
+        boolean isOptedOut = mController.isCaptionStreamOptedOut();
+        if (mODICaptionsIcon.getOptedOut() != isOptedOut) {
+            mHandler.post(() -> mODICaptionsIcon.setOptedOut(isOptedOut));
+        }
     }
 
     private void onCaptionIconClicked() {
@@ -952,7 +956,7 @@
     }
 
     private void updateVolumeRowH(VolumeRow row) {
-        if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream);
+        if (D.BUG) Log.i(TAG, "updateVolumeRowH s=" + row.stream);
         if (mState == null) return;
         final StreamState ss = mState.states.get(row.stream);
         if (ss == null) return;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 29505a2..632b0c0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -39,10 +39,12 @@
 import android.widget.TextClock;
 
 import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -70,7 +72,10 @@
 
     @Before
     public void setUp() {
-        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        InjectionInflationController inflationController = new InjectionInflationController(
+                SystemUIFactory.getInstance().getRootComponent());
+        LayoutInflater layoutInflater = inflationController
+                .injectable(LayoutInflater.from(getContext()));
         mKeyguardClockSwitch =
                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
         mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 3582ab01..31ea39c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -24,8 +24,10 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
 
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -48,7 +50,10 @@
     @Before
     public void setUp() {
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
-        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        InjectionInflationController inflationController = new InjectionInflationController(
+                SystemUIFactory.getInstance().getRootComponent());
+        LayoutInflater layoutInflater = inflationController
+                .injectable(LayoutInflater.from(getContext()));
         mKeyguardStatusView =
                 (KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null);
         org.mockito.MockitoAnnotations.initMocks(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index b8add89..cd84805 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -43,7 +43,6 @@
     @Spy
     private ExpandedAnimationController mExpandedController =
             new ExpandedAnimationController(new Point(500, 1000) /* displaySize */);
-
     private int mStackOffset;
     private float mBubblePadding;
     private float mBubbleSize;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
index a50919b..38a90f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -20,12 +20,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 
 import android.os.SystemClock;
 import android.testing.AndroidTestingRunner;
@@ -68,7 +67,8 @@
         // offset, and don't actually remove views immediately (since most implementations will wait
         // to animate child views out before actually removing them).
         mTestableController.setAnimatedProperties(Sets.newHashSet(
-                DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y));
+                DynamicAnimation.TRANSLATION_X,
+                DynamicAnimation.TRANSLATION_Y));
         mTestableController.setChainedProperties(Sets.newHashSet(DynamicAnimation.TRANSLATION_X));
         mTestableController.setOffsetForProperty(
                 DynamicAnimation.TRANSLATION_X, TEST_TRANSLATION_X_OFFSET);
@@ -126,11 +126,11 @@
 
         // Animate the first child's translation X.
         final CountDownLatch animLatch = new CountDownLatch(1);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100,
-                animLatch::countDown);
+
+        mTestableController
+                .animationForChildAtIndex(0)
+                .translationX(100)
+                .start(animLatch::countDown);
         animLatch.await(1, TimeUnit.SECONDS);
 
         // Ensure that the first view has been translated, but not the second one.
@@ -140,60 +140,50 @@
 
     @Test
     public void testUpdateValueXChained() throws InterruptedException {
-        mLayout.setController(mTestableController);
-        addOneMoreThanRenderLimitBubbles();
         testChainedTranslationAnimations();
     }
 
     @Test
-    public void testSetEndListeners() throws InterruptedException {
+    public void testSetEndActions() throws InterruptedException {
         mLayout.setController(mTestableController);
         addOneMoreThanRenderLimitBubbles();
         mTestableController.setChainedProperties(Sets.newHashSet());
 
         final CountDownLatch xLatch = new CountDownLatch(1);
-        OneTimeEndListener xEndListener = Mockito.spy(new OneTimeEndListener() {
+        Runnable xEndAction = Mockito.spy(new Runnable() {
+
             @Override
-            public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
-                    float velocity) {
-                super.onAnimationEnd(animation, canceled, value, velocity);
+            public void run() {
                 xLatch.countDown();
             }
         });
 
         final CountDownLatch yLatch = new CountDownLatch(1);
-        final OneTimeEndListener yEndListener = Mockito.spy(new OneTimeEndListener() {
+        Runnable yEndAction = Mockito.spy(new Runnable() {
+
             @Override
-            public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
-                    float velocity) {
-                super.onAnimationEnd(animation, canceled, value, velocity);
+            public void run() {
                 yLatch.countDown();
             }
         });
 
         // Set end listeners for both x and y.
-        mLayout.setEndListenerForProperty(xEndListener, DynamicAnimation.TRANSLATION_X);
-        mLayout.setEndListenerForProperty(yEndListener, DynamicAnimation.TRANSLATION_Y);
+        mLayout.setEndActionForProperty(xEndAction, DynamicAnimation.TRANSLATION_X);
+        mLayout.setEndActionForProperty(yEndAction, DynamicAnimation.TRANSLATION_Y);
 
         // Animate x, and wait for it to finish.
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(100)
+                .start();
+
         xLatch.await();
         yLatch.await(1, TimeUnit.SECONDS);
 
         // Make sure the x end listener was called only one time, and the y listener was never
         // called since we didn't animate y. Wait 1 second after the original animation end trigger
         // to make sure it doesn't get called again.
-        Mockito.verify(xEndListener, Mockito.after(1000).times(1))
-                .onAnimationEnd(
-                        any(),
-                        eq(false),
-                        eq(100f),
-                        anyFloat());
-        Mockito.verify(yEndListener, Mockito.after(1000).never())
-                .onAnimationEnd(any(), anyBoolean(), anyFloat(), anyFloat());
+        Mockito.verify(xEndAction, Mockito.after(1000).times(1)).run();
+        Mockito.verify(yEndAction, Mockito.after(1000).never()).run();
     }
 
     @Test
@@ -203,39 +193,31 @@
         mTestableController.setChainedProperties(Sets.newHashSet());
 
         final CountDownLatch xLatch = new CountDownLatch(1);
-        OneTimeEndListener xEndListener = Mockito.spy(new OneTimeEndListener() {
+        Runnable xEndListener = Mockito.spy(new Runnable() {
+
             @Override
-            public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
-                    float velocity) {
-                super.onAnimationEnd(animation, canceled, value, velocity);
+            public void run() {
                 xLatch.countDown();
             }
         });
 
         // Set the end listener.
-        mLayout.setEndListenerForProperty(xEndListener, DynamicAnimation.TRANSLATION_X);
+        mLayout.setEndActionForProperty(xEndListener, DynamicAnimation.TRANSLATION_X);
 
         // Animate x, and wait for it to finish.
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(100)
+                .start();
         xLatch.await();
 
         InOrder endListenerCalls = inOrder(xEndListener);
-        endListenerCalls.verify(xEndListener, Mockito.times(1))
-                .onAnimationEnd(
-                        any(),
-                        eq(false),
-                        eq(100f),
-                        anyFloat());
+        endListenerCalls.verify(xEndListener, Mockito.times(1)).run();
 
         // Animate X again, remove the end listener.
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                1000);
-        mLayout.removeEndListenerForProperty(DynamicAnimation.TRANSLATION_X);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(1000)
+                .start();
+        mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_X);
         xLatch.await(1, TimeUnit.SECONDS);
 
         // Make sure the end listener was not called.
@@ -261,10 +243,9 @@
         secondController.setRemoveImmediately(true);
 
         mLayout.setController(secondController);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.SCALE_X,
-                0,
-                1.5f);
+        mTestableController.animationForChildAtIndex(0)
+                .scaleX(1.5f)
+                .start();
 
         waitForPropertyAnimations(DynamicAnimation.SCALE_X);
 
@@ -285,10 +266,9 @@
                 .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X));
 
         mLayout.setController(mTestableController);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100f);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(100f)
+                .start();
 
         waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X);
 
@@ -308,10 +288,9 @@
         assertFalse(mLayout.arePropertiesAnimating(
                 DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y));
 
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(100f)
+                .start();
 
         // Wait for the animations to get underway.
         SystemClock.sleep(50);
@@ -330,14 +309,9 @@
         mLayout.setController(mTestableController);
         addOneMoreThanRenderLimitBubbles();
 
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                1000);
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_Y,
-                0,
-                1000);
+        mTestableController.animationForChildAtIndex(0)
+                .position(1000, 1000)
+                .start();
 
         mLayout.cancelAllAnimations();
 
@@ -367,13 +341,15 @@
 
     /** Standard test of chained translation animations. */
     private void testChainedTranslationAnimations() throws InterruptedException {
+        mLayout.setController(mTestableController);
+        addOneMoreThanRenderLimitBubbles();
+
         assertEquals(0, mLayout.getChildAt(0).getTranslationX(), .1f);
         assertEquals(0, mLayout.getChildAt(1).getTranslationX(), .1f);
 
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_X,
-                0,
-                100);
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(100f)
+                .start();
 
         waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X);
 
@@ -392,10 +368,9 @@
         assertEquals(0, mLayout.getChildAt(1).getTranslationY(), .1f);
 
         // Animate the first child's Y translation.
-        mLayout.animateValueForChildAtIndex(
-                DynamicAnimation.TRANSLATION_Y,
-                0,
-                100);
+        mTestableController.animationForChildAtIndex(0)
+                .translationY(100f)
+                .start();
 
         waitForPropertyAnimations(DynamicAnimation.TRANSLATION_Y);
 
@@ -405,6 +380,75 @@
         assertEquals(0, mLayout.getChildAt(1).getTranslationY(), .1f);
     }
 
+    @Test
+    public void testPhysicsAnimator() throws InterruptedException {
+        mLayout.setController(mTestableController);
+        addOneMoreThanRenderLimitBubbles();
+
+        Runnable afterAll = Mockito.mock(Runnable.class);
+        Runnable after = Mockito.spy(new Runnable() {
+            int mCallCount = 0;
+
+            @Override
+            public void run() {
+                // Make sure that if only one of the animations has finished, we didn't already call
+                // afterAll.
+                if (mCallCount == 1) {
+                    Mockito.verifyNoMoreInteractions(afterAll);
+                }
+            }
+        });
+
+        // Animate from x = 7 to x = 100, and from y = 100 to 7 = 200, calling 'after' after each
+        // property's animation completes, then call afterAll when they're all complete.
+        mTestableController.animationForChildAtIndex(0)
+                .translationX(7, 100, after)
+                .translationY(100, 200, after)
+                .start(afterAll);
+
+        // We should have immediately set the 'from' values.
+        assertEquals(7, mViews.get(0).getTranslationX(), .01f);
+        assertEquals(100, mViews.get(0).getTranslationY(), .01f);
+
+        waitForPropertyAnimations(
+                DynamicAnimation.TRANSLATION_X,
+                DynamicAnimation.TRANSLATION_Y);
+
+        // We should have called the after callback twice, and afterAll once. We verify in the
+        // mocked callback that afterAll isn't called before both finish.
+        Mockito.verify(after, times(2)).run();
+        Mockito.verify(afterAll).run();
+
+        // Make sure we actually animated the views.
+        assertEquals(100, mViews.get(0).getTranslationX(), .01f);
+        assertEquals(200, mViews.get(0).getTranslationY(), .01f);
+    }
+
+    @Test
+    public void testAnimationsForChildrenFromIndex() throws InterruptedException {
+        // Don't chain since we're going to invoke each animation independently.
+        mTestableController.setChainedProperties(new HashSet<>());
+
+        mLayout.setController(mTestableController);
+
+        addOneMoreThanRenderLimitBubbles();
+
+        Runnable allEnd = Mockito.mock(Runnable.class);
+
+        mTestableController.animationsForChildrenFromIndex(
+                1, (index, animation) -> animation.translationX((index - 1) * 50))
+            .startAll(allEnd);
+
+        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X);
+
+        assertEquals(0, mViews.get(0).getTranslationX(), .1f);
+        assertEquals(0, mViews.get(1).getTranslationX(), .1f);
+        assertEquals(50, mViews.get(2).getTranslationX(), .1f);
+        assertEquals(100, mViews.get(3).getTranslationX(), .1f);
+
+        Mockito.verify(allEnd, times(1)).run();
+    }
+
     /**
      * Animation controller with configuration methods whose return values can be set by individual
      * tests.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
index d94b669..9fce092 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
@@ -28,6 +28,7 @@
 import android.widget.FrameLayout;
 
 import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -38,6 +39,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -113,25 +115,17 @@
             throws InterruptedException {
         final CountDownLatch animLatch = new CountDownLatch(properties.length);
         for (DynamicAnimation.ViewProperty property : properties) {
-            mLayout.setTestEndListenerForProperty(new OneTimeEndListener() {
-                @Override
-                public void onAnimationEnd(DynamicAnimation animation, boolean canceled,
-                        float value,
-                        float velocity) {
-                    super.onAnimationEnd(animation, canceled, value, velocity);
-                    animLatch.countDown();
-                }
-            }, property);
+            mLayout.setTestEndActionForProperty(animLatch::countDown, property);
         }
-        animLatch.await(1, TimeUnit.SECONDS);
+
+        animLatch.await(2, TimeUnit.SECONDS);
     }
 
-    /** Uses a latch to wait for the message queue to finish. */
+    /** Uses a latch to wait for the main thread message queue to finish. */
     void waitForLayoutMessageQueue() throws InterruptedException {
-        // Wait for layout, then the view should be actually removed.
         CountDownLatch layoutLatch = new CountDownLatch(1);
         mMainThreadHandler.post(layoutLatch::countDown);
-        layoutLatch.await(1, TimeUnit.SECONDS);
+        layoutLatch.await(2, TimeUnit.SECONDS);
     }
 
     /**
@@ -145,8 +139,9 @@
 
         @Override
         public void setController(PhysicsAnimationController controller) {
-            mMainThreadHandler.post(() -> super.setController(controller));
-            waitForMessageQueueAndIgnoreIfInterrupted();
+            runOnMainThreadAndBlock(
+                    () -> super.setController(
+                            new MainThreadAnimationControllerWrapper(controller)));
         }
 
         @Override
@@ -160,59 +155,139 @@
         }
 
         @Override
-        protected void animateValueForChildAtIndex(DynamicAnimation.ViewProperty property,
-                int index, float value, float startVel, Runnable after) {
-            mMainThreadHandler.post(() ->
-                    super.animateValueForChildAtIndex(property, index, value, startVel, after));
-        }
-
-        @Override
         public WindowInsets getRootWindowInsets() {
             return mWindowInsets;
         }
 
         @Override
-        public void removeView(View view) {
-            mMainThreadHandler.post(() ->
-                    super.removeView(view));
-            waitForMessageQueueAndIgnoreIfInterrupted();
+        public void addView(View child, int index) {
+            child.setTag(R.id.physics_animator_tag, new TestablePhysicsPropertyAnimator(child));
+            super.addView(child, index);
         }
 
         @Override
         public void addView(View child, int index, ViewGroup.LayoutParams params) {
-            mMainThreadHandler.post(() ->
-                    super.addView(child, index, params));
-            waitForMessageQueueAndIgnoreIfInterrupted();
+            child.setTag(R.id.physics_animator_tag, new TestablePhysicsPropertyAnimator(child));
+            super.addView(child, index, params);
         }
 
         /**
-         * Wait for the queue but just catch and print the exception if interrupted, since we can't
-         * just add the exception to the overridden methods' signatures.
+         * Sets an end action that will be called after the 'real' end action that was already set.
          */
-        private void waitForMessageQueueAndIgnoreIfInterrupted() {
-            try {
-                waitForLayoutMessageQueue();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
+        private void setTestEndActionForProperty(
+                Runnable action, DynamicAnimation.ViewProperty property) {
+            final Runnable realEndAction = mEndActionForProperty.get(property);
+
+            setEndActionForProperty(() -> {
+                if (realEndAction != null) {
+                    realEndAction.run();
+                }
+
+                action.run();
+            }, property);
+        }
+
+        /** PhysicsPropertyAnimator that posts its animations to the main thread. */
+        protected class TestablePhysicsPropertyAnimator extends PhysicsPropertyAnimator {
+            public TestablePhysicsPropertyAnimator(View view) {
+                super(view);
+            }
+
+            @Override
+            protected void animateValueForChild(DynamicAnimation.ViewProperty property, View view,
+                    float value, float startVel, long startDelay, Runnable[] afterCallbacks) {
+                mMainThreadHandler.post(() -> super.animateValueForChild(
+                        property, view, value, startVel, startDelay, afterCallbacks));
             }
         }
 
         /**
-         * Sets an end listener that will be called after the 'real' end listener that was already
-         * set.
+         * Wrapper around an animation controller that dispatches methods that could start
+         * animations to the main thread.
          */
-        private void setTestEndListenerForProperty(DynamicAnimation.OnAnimationEndListener listener,
-                DynamicAnimation.ViewProperty property) {
-            final DynamicAnimation.OnAnimationEndListener realEndListener =
-                    mEndListenerForProperty.get(property);
+        protected class MainThreadAnimationControllerWrapper extends PhysicsAnimationController {
 
-            setEndListenerForProperty((animation, canceled, value, velocity) -> {
-                if (realEndListener != null) {
-                    realEndListener.onAnimationEnd(animation, canceled, value, velocity);
+            private final PhysicsAnimationController mWrappedController;
+
+            protected MainThreadAnimationControllerWrapper(PhysicsAnimationController controller) {
+                mWrappedController = controller;
+            }
+
+            @Override
+            protected void setLayout(PhysicsAnimationLayout layout) {
+                mWrappedController.setLayout(layout);
+            }
+
+            @Override
+            protected PhysicsAnimationLayout getLayout() {
+                return mWrappedController.getLayout();
+            }
+
+            @Override
+            Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
+                return mWrappedController.getAnimatedProperties();
+            }
+
+            @Override
+            int getNextAnimationInChain(DynamicAnimation.ViewProperty property, int index) {
+                return mWrappedController.getNextAnimationInChain(property, index);
+            }
+
+            @Override
+            float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
+                return mWrappedController.getOffsetForChainedPropertyAnimation(property);
+            }
+
+            @Override
+            SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) {
+                return mWrappedController.getSpringForce(property, view);
+            }
+
+            @Override
+            void onChildAdded(View child, int index) {
+                runOnMainThreadAndBlock(() -> mWrappedController.onChildAdded(child, index));
+            }
+
+            @Override
+            void onChildRemoved(View child, int index, Runnable finishRemoval) {
+                runOnMainThreadAndBlock(
+                        () -> mWrappedController.onChildRemoved(child, index, finishRemoval));
+            }
+
+            @Override
+            protected void setChildVisibility(View child, int index, int visibility) {
+                mWrappedController.setChildVisibility(child, index, visibility);
+            }
+
+            @Override
+            protected PhysicsPropertyAnimator animationForChild(View child) {
+                PhysicsPropertyAnimator animator =
+                        (PhysicsPropertyAnimator) child.getTag(R.id.physics_animator_tag);
+
+                if (!(animator instanceof TestablePhysicsPropertyAnimator)) {
+                    animator = new TestablePhysicsPropertyAnimator(child);
+                    child.setTag(R.id.physics_animator_tag, animator);
                 }
 
-                listener.onAnimationEnd(animation, canceled, value, velocity);
-            }, property);
+                return animator;
+            }
+        }
+    }
+
+    /**
+     * Posts the given Runnable on the main thread, and blocks the calling thread until it's run.
+     */
+    private void runOnMainThreadAndBlock(Runnable action) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mMainThreadHandler.post(() -> {
+            action.run();
+            latch.countDown();
+        });
+
+        try {
+            latch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 2ee73f3..096f205 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -209,6 +209,9 @@
         final PointF prevStackPos = mStackController.getStackPosition();
 
         mLayout.removeAllViews();
+
+        waitForLayoutMessageQueue();
+
         mLayout.addView(new FrameLayout(getContext()));
 
         waitForLayoutMessageQueue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 5a1f24a..1bcf880 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -312,7 +312,6 @@
         return new BubbleMetadata.Builder()
                 .setIntent(bubbleIntent)
                 .setDeleteIntent(deleteIntent)
-                .setTitle("bubble title")
                 .setIcon(Icon.createWithResource(mContext, R.drawable.android))
                 .setDesiredHeight(314)
                 .build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
index eec836f..dfe2913 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
@@ -23,7 +23,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,7 +37,10 @@
     @Test
     public void testInflation_doesntCrash() {
         com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
-        LayoutInflater inflater = LayoutInflater.from(getContext());
+        InjectionInflationController inflationController = new InjectionInflationController(
+                SystemUIFactory.getInstance().getRootComponent());
+        LayoutInflater inflater = inflationController
+                .injectable(LayoutInflater.from(getContext()));
         inflater.inflate(R.layout.keyguard_presentation, null);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 6889c57..232c6a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -27,6 +27,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.AmbientPulseManager;
@@ -38,6 +39,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -104,7 +106,10 @@
     private class TestableNotificationPanelView extends NotificationPanelView {
         TestableNotificationPanelView(NotificationWakeUpCoordinator coordinator,
                 PulseExpansionHandler expansionHandler) {
-            super(NotificationPanelViewTest.this.mContext, null, coordinator, expansionHandler);
+            super(NotificationPanelViewTest.this.mContext, null,
+                    new InjectionInflationController(
+                            SystemUIFactory.getInstance().getRootComponent()),
+                    coordinator, expansionHandler);
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index a15e89c..b522344 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -39,7 +39,10 @@
 	IconShapeRoundedRectOverlay \
 	IconShapeSquareOverlay \
 	IconShapeSquircleOverlay \
-	IconShapeTeardropOverlay
+	IconShapeTeardropOverlay \
+	NavigationBarMode3ButtonOverlay \
+	NavigationBarMode2ButtonOverlay \
+	NavigationBarModeGesturalOverlay
 
 include $(BUILD_PHONY_PACKAGE)
 include $(CLEAR_VARS)
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
new file mode 100644
index 0000000..410d6d8
--- /dev/null
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+#  Copyright 2018, 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_RRO_THEME := NavigationBarMode2Button
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := NavigationBarMode2ButtonOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/AndroidManifest.xml b/packages/overlays/NavigationBarMode2ButtonOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..970380f
--- /dev/null
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2018, 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="com.android.internal.systemui.navbar.twobutton"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <overlay android:targetPackage="android"
+        android:category="com.android.internal.navigation_bar_mode"
+        android:priority="1"/>
+
+    <application android:label="@string/navigation_bar_mode_title" android:hasCode="false"/>
+</manifest>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/config.xml b/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/config.xml
new file mode 100644
index 0000000..b353322
--- /dev/null
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, 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>
+    <!-- Controls the navigation bar interaction mode:
+         0: 3 button mode (back, home, overview buttons)
+         1: 2 button mode (back, home buttons + swipe up for overview)
+         2: gestures only for back, home and overview -->
+    <integer name="config_navBarInteractionMode">1</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/strings.xml b/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/strings.xml
new file mode 100644
index 0000000..1696ecf
--- /dev/null
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of overlay [CHAR LIMIT=64] -->
+    <string name="navigation_bar_mode_title" translatable="false">2 Button Navigation Bar</string>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
new file mode 100644
index 0000000..2bc9a6a
--- /dev/null
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+#  Copyright 2018, 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_RRO_THEME := NavigationBarMode3Button
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := NavigationBarMode3ButtonOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/AndroidManifest.xml b/packages/overlays/NavigationBarMode3ButtonOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..628fc1d
--- /dev/null
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2018, 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="com.android.internal.systemui.navbar.threebutton"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <overlay android:targetPackage="android"
+        android:category="com.android.internal.navigation_bar_mode"
+        android:priority="1"/>
+
+    <application android:label="@string/navigation_bar_mode_title" android:hasCode="false"/>
+</manifest>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/config.xml b/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/config.xml
new file mode 100644
index 0000000..7bd0a14
--- /dev/null
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, 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>
+    <!-- Controls the navigation bar interaction mode:
+         0: 3 button mode (back, home, overview buttons)
+         1: 2 button mode (back, home buttons + swipe up for overview)
+         2: gestures only for back, home and overview -->
+    <integer name="config_navBarInteractionMode">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/strings.xml b/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/strings.xml
new file mode 100644
index 0000000..201b9e9
--- /dev/null
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of overlay [CHAR LIMIT=64] -->
+    <string name="navigation_bar_mode_title" translatable="false">3 Button Navigation Bar</string>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
new file mode 100644
index 0000000..5f7e0eb
--- /dev/null
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+#  Copyright 2018, 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_RRO_THEME := NavigationBarModeGestural
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := NavigationBarModeGesturalOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/AndroidManifest.xml b/packages/overlays/NavigationBarModeGesturalOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..aff82d8
--- /dev/null
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2018, 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="com.android.internal.systemui.navbar.gestural"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <overlay android:targetPackage="android"
+        android:category="com.android.internal.navigation_bar_mode"
+        android:priority="1"/>
+
+    <application android:label="@string/navigation_bar_mode_title" android:hasCode="false"/>
+</manifest>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
new file mode 100644
index 0000000..48c3769
--- /dev/null
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, 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>
+    <!-- Controls the navigation bar interaction mode:
+         0: 3 button mode (back, home, overview buttons)
+         1: 2 button mode (back, home buttons + swipe up for overview)
+         2: gestures only for back, home and overview -->
+    <integer name="config_navBarInteractionMode">2</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/strings.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/strings.xml
new file mode 100644
index 0000000..8d38916
--- /dev/null
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of overlay [CHAR LIMIT=64] -->
+    <string name="navigation_bar_mode_title" translatable="false">Gestural Navigation Bar</string>
+</resources>
\ No newline at end of file
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 7447331..95abd05 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -74,6 +74,9 @@
     // The view switched to summary mode (most relevant for notifications)
     TYPE_COLLAPSE = 14;
 
+    // The action results an error.
+    TYPE_ERROR = 15;
+
     // The notification was adjusted by the assistant. Enum value is
     // out of sequence due to b/122737498.
     TYPE_NOTIFICATION_ASSISTANT_ADJUSTMENT = 1573;
@@ -7138,6 +7141,14 @@
     // OS: Q
     DISPLAY_POLICY = 1696;
 
+    // Biometric authentication.
+    //    TYPE: SUCCESS, FAILURE or ERROR
+    //    SUBTYPE: 0 is fingerprint, 1 is face, 2 is iris and 3 is unknown.
+    // OS: Q
+    BIOMETRIC_AUTH = 1697;
+
+    // Settings > Display > Theme
+    DARK_UI_SETTINGS = 1698;
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index 833eaa0..6bb5370 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -94,10 +94,10 @@
         }
 
         @Override
-        public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+        public void notifyLaunchLocationShown(@NonNull AppPredictionSessionId sessionId,
                 @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
             runForUserLocked((service) ->
-                    service.notifyLocationShownLocked(sessionId, launchLocation, targetIds));
+                    service.notifyLaunchLocationShownLocked(sessionId, launchLocation, targetIds));
         }
 
         @Override
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 24d592c..430abf5 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -111,11 +111,11 @@
      * Records when a launch location is shown.
      */
     @GuardedBy("mLock")
-    public void notifyLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
+    public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
             @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
         final RemoteAppPredictionService service = getRemoteServiceLocked();
         if (service != null) {
-            service.notifyLocationShown(sessionId, launchLocation, targetIds);
+            service.notifyLaunchLocationShown(sessionId, launchLocation, targetIds);
         }
     }
 
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index 922b327..21088e4 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -85,9 +85,10 @@
     /**
      * Records when a launch location is shown.
      */
-    public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+    public void notifyLaunchLocationShown(@NonNull AppPredictionSessionId sessionId,
             @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
-        scheduleAsyncRequest((s) -> s.notifyLocationShown(sessionId, launchLocation, targetIds));
+        scheduleAsyncRequest((s)
+                -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
     }
 
     /**
diff --git a/services/art-profile b/services/art-profile
index 6368c63..f0b9234 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -1136,7 +1136,7 @@
 Lcom/android/server/DropBoxManagerService$EntryFile;
 Lcom/android/server/DropBoxManagerService$FileList;
 Lcom/android/server/DropBoxManagerService;
-Lcom/android/server/DynamicAndroidService;
+Lcom/android/server/DynamicSystemService;
 Lcom/android/server/EntropyMixer$1;
 Lcom/android/server/EntropyMixer$2;
 Lcom/android/server/EntropyMixer;
@@ -4769,9 +4769,9 @@
 PLcom/android/server/DropBoxManagerService$EntryFile;->getFile(Ljava/io/File;)Ljava/io/File;
 PLcom/android/server/DropBoxManagerService;->checkPermission(ILjava/lang/String;)Z
 PLcom/android/server/DropBoxManagerService;->getNextEntry(Ljava/lang/String;JLjava/lang/String;)Landroid/os/DropBoxManager$Entry;
-PLcom/android/server/DynamicAndroidService;->connect(Landroid/os/IBinder$DeathRecipient;)Landroid/gsi/IGsiService;
-PLcom/android/server/DynamicAndroidService;->getGsiService()Landroid/gsi/IGsiService;
-PLcom/android/server/DynamicAndroidService;->isInUse()Z
+PLcom/android/server/DynamicSystemService;->connect(Landroid/os/IBinder$DeathRecipient;)Landroid/gsi/IGsiService;
+PLcom/android/server/DynamicSystemService;->getGsiService()Landroid/gsi/IGsiService;
+PLcom/android/server/DynamicSystemService;->isInUse()Z
 PLcom/android/server/EntropyMixer$1;->handleMessage(Landroid/os/Message;)V
 PLcom/android/server/EntropyMixer$2;->onReceive(Landroid/content/Context;Landroid/content/Intent;)V
 PLcom/android/server/EventLogTags;->writeBatterySaverMode(IIIIILjava/lang/String;I)V
@@ -15043,7 +15043,7 @@
 SPLcom/android/server/DropBoxManagerService;->onBootPhase(I)V
 SPLcom/android/server/DropBoxManagerService;->onStart()V
 SPLcom/android/server/DropBoxManagerService;->trimToFit()J
-SPLcom/android/server/DynamicAndroidService;-><init>(Landroid/content/Context;)V
+SPLcom/android/server/DynamicSystemService;-><init>(Landroid/content/Context;)V
 SPLcom/android/server/EntropyMixer;-><init>(Landroid/content/Context;)V
 SPLcom/android/server/EntropyMixer;-><init>(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 SPLcom/android/server/EntropyMixer;->addDeviceSpecificEntropy()V
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index c1c125d..87a265c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -80,6 +80,7 @@
 import com.android.server.LocalServices;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
 import com.android.server.infra.SecureSettingsServiceNameResolver;
 
 import java.io.FileDescriptor;
@@ -132,6 +133,12 @@
     @GuardedBy("sLock")
     private static int sVisibleDatasetsMaxCount = 0;
 
+    /**
+     * Object used to set the name of the augmented autofill service.
+     */
+    @NonNull
+    final FrameworkResourcesServiceNameResolver mAugmentedAutofillResolver;
+
     private final AutoFillUI mUi;
 
     private final LocalLog mRequestsHistory = new LocalLog(20);
@@ -200,6 +207,11 @@
                 getServiceForUserLocked(userId);
             }
         }
+
+        mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
+                com.android.internal.R.string.config_defaultAugmentedAutofillService);
+        mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
+                (u, s) -> getServiceForUserLocked(u).updateRemoteAugmentedAutofillService());
     }
 
     @Override // from AbstractMasterSystemService
@@ -521,7 +533,7 @@
                 new FieldClassificationStrategy(getContext(), UserHandle.USER_CURRENT);
 
         strategy.calculateScores(callback, Arrays.asList(AutofillValue.forText(value1)),
-                new String[] { value2 }, null, algorithmName, null, null, null);
+                new String[] { value2 }, new String[] { null }, algorithmName, null, null, null);
     }
 
     // Called by Shell command.
@@ -549,37 +561,19 @@
                     + MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS + " (called with " + durationMs + ")");
         }
 
-        synchronized (mLock) {
-            final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service != null) {
-                service.mAugmentedAutofillResolver.setTemporaryService(userId, serviceName,
-                        durationMs);
-            }
-        }
+        mAugmentedAutofillResolver.setTemporaryService(userId, serviceName, durationMs);
     }
 
     // Called by Shell command
     void resetTemporaryAugmentedAutofillService(@UserIdInt int userId) {
         enforceCallingPermissionForManagement();
-        synchronized (mLock) {
-            final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service != null) {
-                service.mAugmentedAutofillResolver.resetTemporaryService(userId);
-            }
-        }
+        mAugmentedAutofillResolver.resetTemporaryService(userId);
     }
 
     // Called by Shell command
     boolean isDefaultAugmentedServiceEnabled(@UserIdInt int userId) {
         enforceCallingPermissionForManagement();
-
-        synchronized (mLock) {
-            final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service != null) {
-                return service.mAugmentedAutofillResolver.isDefaultServiceEnabled(userId);
-            }
-        }
-        return false;
+        return mAugmentedAutofillResolver.isDefaultServiceEnabled(userId);
     }
 
     // Called by Shell command
@@ -590,7 +584,7 @@
         synchronized (mLock) {
             final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
             if (service != null) {
-                final boolean changed = service.mAugmentedAutofillResolver
+                final boolean changed = mAugmentedAutofillResolver
                         .setDefaultServiceEnabled(userId, enabled);
                 if (changed) {
                     service.updateRemoteAugmentedAutofillService();
@@ -942,12 +936,14 @@
 
     final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
         @Override
-        public void addClient(IAutoFillManagerClient client, int userId,
-                @NonNull IResultReceiver receiver) {
+        public void addClient(IAutoFillManagerClient client, ComponentName componentName,
+                int userId, IResultReceiver receiver) {
             int flags = 0;
             synchronized (mLock) {
-                if (getServiceForUserLocked(userId).addClientLocked(client)) {
-                    flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED;
+                final int enabledFlags = getServiceForUserLocked(userId).addClientLocked(client,
+                        componentName);
+                if (enabledFlags != 0) {
+                    flags |= enabledFlags;
                 }
                 if (sDebug) {
                     flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
@@ -1346,6 +1342,7 @@
                     pw.print(" sVerbose: "); pw.println(realVerbose);
                     // Dump per-user services
                     dumpLocked("", pw);
+                    mAugmentedAutofillResolver.dumpShort(pw); pw.println();
                     pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
                     pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount);
                     if (sFullScreenMode != null) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 720d319..ff284dc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -18,6 +18,8 @@
 
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
+import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
+import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
 import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
@@ -38,6 +40,7 @@
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -54,7 +57,6 @@
 import android.service.autofill.FieldClassification.Match;
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillEventHistory.Event;
-import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.service.autofill.UserData;
@@ -82,7 +84,6 @@
 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.infra.AbstractPerUserSystemService;
-import com.android.server.infra.FrameworkResourcesServiceNameResolver;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -158,13 +159,6 @@
     /** When was {@link PruneTask} last executed? */
     private long mLastPrune = 0;
 
-    // TODO(b/128911469): move to AutofillManagerService
-    /**
-     * Object used to set the name of the augmented autofill service.
-     */
-    @NonNull
-    final FrameworkResourcesServiceNameResolver mAugmentedAutofillResolver;
-
     /**
      * Reference to the {@link RemoteAugmentedAutofillService}, is set on demand.
      */
@@ -194,11 +188,6 @@
         mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
         mAutofillCompatState = autofillCompatState;
 
-        mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(master.getContext(),
-                com.android.internal.R.string.config_defaultAugmentedAutofillService);
-        mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
-                (u, s) -> updateRemoteAugmentedAutofillService());
-
         updateLocked(disabled);
     }
 
@@ -242,13 +231,28 @@
         return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
     }
 
+    /**
+     * Adds the client and return the proper flags
+     *
+     * @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be
+     * OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}).
+     */
     @GuardedBy("mLock")
-    boolean addClientLocked(IAutoFillManagerClient client) {
+    int addClientLocked(IAutoFillManagerClient client, ComponentName componentName) {
         if (mClients == null) {
             mClients = new RemoteCallbackList<>();
         }
         mClients.register(client);
-        return isEnabledLocked();
+
+        if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
+
+        // Check if it's enabled for augmented autofill
+        if (isSetupCompletedLocked() && isWhitelistedForAugmentedAutofillLocked(componentName)) {
+            return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
+        }
+
+        // No flags / disabled
+        return 0;
     }
 
     @GuardedBy("mLock")
@@ -286,7 +290,7 @@
      *
      * @return {@code long} whose right-most 32 bits represent the session id (which is always
      * non-negative), and the left-most contains extra flags (currently either {@code 0} or
-     * {@link FillRequest#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
+     * {@link AutofillManager#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
      */
     @GuardedBy("mLock")
     long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
@@ -294,26 +298,27 @@
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
             @NonNull ComponentName componentName, boolean compatMode,
             boolean bindInstantServiceAllowed, int flags) {
-        if (!isEnabledLocked()) {
+        // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled
+        // but the package is whitelisted for augmented autofill
+        boolean forAugmentedAutofillOnly = (flags
+                & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
+        if (!isEnabledLocked() && !forAugmentedAutofillOnly) {
             return 0;
         }
 
-        final String shortComponentName = componentName.toShortString();
-        boolean forAugmentedAutofillOnly = false;
-
-        if (isAutofillDisabledLocked(componentName)) {
-            // Service disabled autofill; that means no session, unless the activity is whitelisted
-            // for augmented autofill
+        if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(componentName)) {
+            // Standard autofill is enabled, but service disabled autofill for this activity; that
+            // means no session, unless the activity is whitelisted for augmented autofill
             if (isWhitelistedForAugmentedAutofillLocked(componentName)) {
                 if (sDebug) {
-                    Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but "
+                    Slog.d(TAG, "startSession(" + componentName + "): disabled by service but "
                             + "whitelisted for augmented autofill");
                 }
                 forAugmentedAutofillOnly = true;
 
             } else {
                 if (sDebug) {
-                    Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because "
+                    Slog.d(TAG, "startSession(" + componentName + "): ignored because "
                             + "disabled by service and not whitelisted for augmented autofill");
                 }
                 final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
@@ -323,7 +328,7 @@
                             /* autofillableIds= */ null);
                 } catch (RemoteException e) {
                     Slog.w(TAG,
-                            "Could not notify " + shortComponentName + " that it's disabled: " + e);
+                            "Could not notify " + componentName + " that it's disabled: " + e);
                 }
 
                 return NO_SESSION;
@@ -345,9 +350,11 @@
             return NO_SESSION;
         }
 
+        // Service can be null when it's only for augmented autofill
+        String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName;
         final String historyItem =
-                "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
-                + " s=" + mInfo.getServiceInfo().packageName
+                "id=" + newSession.id + " uid=" + uid + " a=" + componentName.toShortString()
+                + " s=" + servicePackageName
                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
                 + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
         mMaster.logRequestLocked(historyItem);
@@ -485,9 +492,12 @@
 
         assertCallerLocked(componentName, compatMode);
 
+        // It's null when the session is just for augmented autofill
+        final ComponentName serviceComponentName = mInfo == null ? null
+                : mInfo.getServiceInfo().getComponentName();
         final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
                 sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
-                mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(),
+                mUiLatencyHistory, mWtfHistory, serviceComponentName,
                 componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
                 flags);
         mSessions.put(newSession.id, newSession);
@@ -929,8 +939,7 @@
                 .getString(R.string.config_defaultAutofillService));
 
         pw.print(prefix); pw.println("mAugmentedAutofillNamer: ");
-        pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw); pw.println();
-        pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println();
+        pw.print(prefix2); mMaster.mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println();
 
         if (mRemoteAugmentedAutofillService != null) {
             pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
@@ -1087,7 +1096,7 @@
     @GuardedBy("mLock")
     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
         if (mRemoteAugmentedAutofillService == null) {
-            final String serviceName = mAugmentedAutofillResolver.getServiceName(mUserId);
+            final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
             if (serviceName == null) {
                 if (mMaster.verbose) {
                     Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): not set");
@@ -1095,8 +1104,8 @@
                 return null;
             }
             final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
-                    .getComponentName(
-                            serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
+                    .getComponentName(serviceName, mUserId,
+                            mMaster.mAugmentedAutofillResolver.isTemporary(mUserId));
             if (pair == null) return null;
 
             mRemoteAugmentedAutofillServiceInfo = pair.first;
@@ -1126,7 +1135,8 @@
     }
 
     /**
-     * Called when the {@link #mAugmentedAutofillResolver} changed (among other places).
+     * Called when the {@link AutofillManagerService#mAugmentedAutofillResolver}
+     * changed (among other places).
      */
     void updateRemoteAugmentedAutofillService() {
         synchronized (mLock) {
@@ -1203,6 +1213,18 @@
 
     @GuardedBy("mLock")
     boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
+        if (Build.IS_USER && mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)) {
+            final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
+            final ComponentName component = ComponentName.unflattenFromString(serviceName);
+            final String servicePackage = component == null ? null : component.getPackageName();
+            final String packageName = componentName.getPackageName();
+            if (!packageName.equals(servicePackage)) {
+                Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill while "
+                        + "using temporary service " + servicePackage);
+                return false;
+            }
+        }
+
         return mAugmentedWhitelistHelper.isWhitelisted(componentName);
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f08bab3..c62794d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -185,6 +185,12 @@
     @GuardedBy("mLock")
     private DeathRecipient mClientVulture;
 
+    /**
+     * Reference to the remote service.
+     *
+     * <p>Only {@code null} when the session is for augmented autofill only.
+     */
+    @Nullable
     private final RemoteFillService mRemoteFillService;
 
     @GuardedBy("mLock")
@@ -293,6 +299,11 @@
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
         @Override
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
+            if (mRemoteFillService == null) {
+                wtf(null, "onHandleAssistData() called without a remote service. "
+                        + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+                return;
+            }
             final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE);
             if (structure == null) {
                 Slog.e(TAG, "No assist structure - app might have crashed providing it");
@@ -527,6 +538,11 @@
      */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
+        if (mRemoteFillService == null) {
+            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
+                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+            return;
+        }
         final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
         // Remove the FillContext as there will never be a response for the service
@@ -608,7 +624,7 @@
             @NonNull Context context, @NonNull Handler handler, int userId, @NonNull Object lock,
             int sessionId, int taskId, int uid, @NonNull IBinder activityToken,
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
-            @NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName,
+            @NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
             @NonNull ComponentName componentName, boolean compatMode,
             boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
         if (sessionId < 0) {
@@ -623,8 +639,9 @@
         mLock = lock;
         mUi = ui;
         mHandler = handler;
-        mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this,
-                bindInstantServiceAllowed);
+        mRemoteFillService = serviceComponentName == null ? null
+                : new RemoteFillService(context, serviceComponentName, userId, this,
+                        bindInstantServiceAllowed);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
@@ -2035,6 +2052,11 @@
                     + id + " destroyed");
             return;
         }
+        if (mRemoteFillService == null) {
+            wtf(null, "callSaveLocked() called without a remote service. "
+                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+            return;
+        }
 
         if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
 
@@ -2637,17 +2659,16 @@
         mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked();
         if (mAugmentedAutofillDestroyer == null) {
             if (sVerbose) {
-                Slog.v(TAG, "canceling session " + id + " when server returned null and there is no"
-                        + " AugmentedAutofill for user. AutofillableIds: " + autofillableIds);
+                Slog.v(TAG, "canceling session " + id + " when service returned null and it cannot "
+                        + "be augmented. AutofillableIds: " + autofillableIds);
             }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
             removeSelf();
         } else {
             if (sVerbose) {
-                Slog.v(TAG, "keeping session " + id + " when server returned null but "
-                        + "there is an AugmentedAutofill for user. AutofillableIds: "
-                        + autofillableIds);
+                Slog.v(TAG, "keeping session " + id + " when service returned null but "
+                        + "it can be augmented. AutofillableIds: " + autofillableIds);
             }
             mAugmentedAutofillableIds = autofillableIds;
         }
@@ -2665,7 +2686,10 @@
         // Check if Smart Suggestions is supported...
         final @SmartSuggestionMode int supportedModes = mService
                 .getSupportedSmartSuggestionModesLocked();
-        if (supportedModes == 0) return null;
+        if (supportedModes == 0) {
+            if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no supported modes");
+            return null;
+        }
 
         // ...then if the service is set for the user
 
@@ -2690,14 +2714,6 @@
             return null;
         }
 
-        if (sVerbose) {
-            Slog.v(TAG, "calling Augmented Autofill Service ("
-                    + remoteService.getComponentName().toShortString() + ") on view "
-                    + mCurrentViewId + " using suggestion mode "
-                    + getSmartSuggestionModeToString(mode)
-                    + " when server returned null for session " + this.id);
-        }
-
         final boolean isWhitelisted = mService
                 .isWhitelistedForAugmentedAutofillLocked(mComponentName);
 
@@ -2711,12 +2727,20 @@
 
         if (!isWhitelisted) {
             if (sVerbose) {
-                Slog.v(TAG, mComponentName.toShortString() + " is not whitelisted for "
-                        + "augmented autofill");
+                Slog.v(TAG, "triggerAugmentedAutofillLocked(): "
+                        + ComponentName.flattenToShortString(mComponentName) + " not whitelisted ");
             }
             return null;
         }
 
+        if (sVerbose) {
+            Slog.v(TAG, "calling Augmented Autofill Service ("
+                    + ComponentName.flattenToShortString(remoteService.getComponentName())
+                    + ") on view " + mCurrentViewId + " using suggestion mode "
+                    + getSmartSuggestionModeToString(mode)
+                    + " when server returned null for session " + this.id);
+        }
+
         final ViewState viewState = mViewStates.get(mCurrentViewId);
         viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
         final AutofillValue currentValue = viewState.getCurrentValue();
@@ -3045,7 +3069,9 @@
             pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
             pw.println(mAugmentedAutofillableIds);
         }
-        mRemoteFillService.dump(prefix, pw);
+        if (mRemoteFillService != null) {
+            mRemoteFillService.dump(prefix, pw);
+        }
     }
 
     private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9995d8e..b2760e0 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,12 @@
 
 import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
+import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
+
+import static com.android.internal.util.SyncResultReceiver.bundleFor;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -57,7 +63,6 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.SyncResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -167,6 +172,22 @@
     }
 
     @Override // from AbstractMasterSystemService
+    protected void onServicePackageUpdatingLocked(int userId) {
+        final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageUpdatingLocked();
+        }
+    }
+
+    @Override // from AbstractMasterSystemService
+    protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+        final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageUpdatedLocked();
+        }
+    }
+
+    @Override // from AbstractMasterSystemService
     protected void enforceCallingPermissionForManagement() {
         getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
     }
@@ -414,8 +435,7 @@
         if (isService) return true;
 
         try {
-            result.send(ContentCaptureManager.RESULT_CODE_NOT_SERVICE,
-                    /* resultData= */ null);
+            result.send(RESULT_CODE_SECURITY_EXCEPTION, /* resultData= */ null);
         } catch (RemoteException e) {
             Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
         }
@@ -518,8 +538,7 @@
                 connectedServiceComponentName = service.getServiceComponentName();
             }
             try {
-                result.send(/* resultCode= */ 0,
-                        SyncResultReceiver.bundleFor(connectedServiceComponentName));
+                result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName));
             } catch (RemoteException e) {
                 Slog.w(mTag, "Unable to send service component name: " + e);
             }
@@ -547,14 +566,40 @@
                 enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
             }
             try {
-                result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
-                        : ContentCaptureManager.RESULT_CODE_FALSE, /* resultData= */null);
+                result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null);
             } catch (RemoteException e) {
                 Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
             }
         }
 
         @Override
+        public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
+            try {
+                enforceCallingPermissionForManagement();
+            } catch (SecurityException e) {
+                try {
+                    result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
+                } catch (RemoteException e2) {
+                    Slog.w(mTag, "Unable to send getServiceSettingsIntent() exception: " + e2);
+                    return;
+                }
+            }
+
+            final int userId = UserHandle.getCallingUserId();
+            final ComponentName componentName;
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                if (service == null) return;
+                componentName = service.getServiceSettingsActivityLocked();
+            }
+            try {
+                result.send(RESULT_CODE_OK, bundleFor(componentName));
+            } catch (RemoteException e) {
+                Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index d7d97b3..d909736 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -40,6 +40,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
@@ -74,7 +75,7 @@
         AbstractPerUserSystemService<ContentCapturePerUserService, ContentCaptureManagerService>
         implements ContentCaptureServiceCallbacks {
 
-    private static final String TAG = ContentCaptureManagerService.class.getSimpleName();
+    private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
 
     @GuardedBy("mLock")
     private final ArrayMap<String, ContentCaptureServerSession> mSessions =
@@ -87,7 +88,8 @@
      * master's cache (for example, because a temporary service was set).
      */
     @GuardedBy("mLock")
-    private RemoteContentCaptureService mRemoteService;
+    @Nullable
+    RemoteContentCaptureService mRemoteService;
 
     private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
             new ContentCaptureServiceRemoteCallback();
@@ -135,6 +137,10 @@
         }
 
         if (!disabled) {
+            if (mMaster.debug) {
+                Slog.d(TAG, "updateRemoteService(): creating new remote service for "
+                        + serviceComponentName);
+            }
             mRemoteService = new RemoteContentCaptureService(mMaster.getContext(),
                     ContentCaptureService.SERVICE_INTERFACE, serviceComponentName,
                     mRemoteServiceCallback, mUserId, this, mMaster.isBindInstantServiceAllowed(),
@@ -182,20 +188,40 @@
                 }
 
                 mZombie = false;
-                final int numSessions = mSessions.size();
-                if (mMaster.debug) {
-                    Slog.d(TAG, "Ressurrecting remote service (" + mRemoteService + ") on "
-                            + numSessions + " sessions");
-                }
-
-                for (int i = 0; i < numSessions; i++) {
-                    final ContentCaptureServerSession session = mSessions.valueAt(i);
-                    session.resurrectLocked();
-                }
+                resurrectSessionsLocked();
             }
         }
     }
 
+    private void resurrectSessionsLocked() {
+        final int numSessions = mSessions.size();
+        if (mMaster.debug) {
+            Slog.d(TAG, "Ressurrecting remote service (" + mRemoteService + ") on "
+                    + numSessions + " sessions");
+        }
+
+        for (int i = 0; i < numSessions; i++) {
+            final ContentCaptureServerSession session = mSessions.valueAt(i);
+            session.resurrectLocked();
+        }
+    }
+
+    void onPackageUpdatingLocked() {
+        final int numSessions = mSessions.size();
+        if (mMaster.debug) {
+            Slog.d(TAG, "Pausing " + numSessions + " sessions while package is updating");
+        }
+        for (int i = 0; i < numSessions; i++) {
+            final ContentCaptureServerSession session = mSessions.valueAt(i);
+            session.pauseLocked();
+        }
+    }
+
+    void onPackageUpdatedLocked() {
+        updateRemoteServiceLocked(!isEnabledLocked());
+        resurrectSessionsLocked();
+    }
+
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
@@ -274,9 +300,12 @@
             return;
         }
 
+        // Make sure service is bound, just in case the initial connection failed somehow
+        mRemoteService.ensureBoundLocked();
+
         final ContentCaptureServerSession newSession = new ContentCaptureServerSession(
-                activityToken, this, mRemoteService, componentName, clientReceiver, taskId,
-                displayId, sessionId, uid, flags);
+                activityToken, this, componentName, clientReceiver, taskId, displayId, sessionId,
+                uid, flags);
         if (mMaster.verbose) {
             Slog.v(TAG, "startSession(): new session for "
                     + ComponentName.flattenToShortString(componentName) + " and id " + sessionId);
@@ -290,21 +319,6 @@
         return mWhitelistHelper.isWhitelisted(componentName);
     }
 
-    /**
-     * @throws IllegalArgumentException if packages or components are empty.
-     */
-    private void setWhitelist(@Nullable List<String> packages,
-            @Nullable List<ComponentName> components) {
-        // TODO(b/122595322): add CTS test for when it's null
-        synchronized (mLock) {
-            if (mMaster.verbose) {
-                Slog.v(TAG, "whitelisting packages: " + packages + " and activities: "
-                        + components);
-            }
-            mWhitelistHelper.setWhitelist(packages, components);
-        }
-    }
-
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void finishSessionLocked(@NonNull String sessionId) {
@@ -332,6 +346,18 @@
         mRemoteService.onUserDataRemovalRequest(request);
     }
 
+    @GuardedBy("mLock")
+    @Nullable
+    public ComponentName getServiceSettingsActivityLocked() {
+        if (mInfo == null) return null;
+
+        final String activityName = mInfo.getSettingsActivity();
+        if (activityName == null) return null;
+
+        final String packageName = mInfo.getServiceInfo().packageName;
+        return new ComponentName(packageName, activityName);
+    }
+
     /**
      * Asserts the component is owned by the caller.
      */
@@ -430,8 +456,13 @@
     }
 
     @GuardedBy("mLock")
+    @Nullable
     ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
         if (!mWhitelistHelper.isWhitelisted(packageName)) {
+            if (packageName.equals(getServicePackageName())) {
+                if (mMaster.verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+                return new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel);
+            }
             if (mMaster.verbose) {
                 Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
             }
@@ -440,6 +471,14 @@
 
         final ArraySet<ComponentName> whitelistedComponents = mWhitelistHelper
                 .getWhitelistedComponents(packageName);
+        if (Build.IS_USER && isTemporaryServiceSetLocked()) {
+            final String servicePackageName = getServicePackageName();
+            if (!packageName.equals(servicePackageName)) {
+                Slog.w(mTag, "Ignoring package " + packageName
+                        + " while using temporary service " + servicePackageName);
+                return null;
+            }
+        }
         ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
                 mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
                 mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
@@ -518,12 +557,16 @@
         @Override
         public void setContentCaptureWhitelist(List<String> packages,
                 List<ComponentName> activities) {
+            // TODO(b/122595322): add CTS test for when it's null
             if (mMaster.verbose) {
-                Slog.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
-                        + activities + ")");
+                Slog.v(TAG, "setContentCaptureWhitelist(" + (packages == null
+                        ? "null_packages" : packages.size() + " packages")
+                        + ", " + (activities == null
+                        ? "null_activities" : activities.size() + " activities") + ")");
             }
-            setWhitelist(packages, activities);
-
+            synchronized (mLock) {
+                mWhitelistHelper.setWhitelist(packages, activities);
+            }
             // TODO(b/119613670): log metrics
         }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index da19836..9b2c05f 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -15,6 +15,12 @@
  */
 package com.android.server.contentcapture;
 
+import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.STATE_ACTIVE;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
+import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_RESURRECTED;
+import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_UPDATING;
+
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.os.IBinder;
@@ -23,7 +29,6 @@
 import android.util.LocalLog;
 import android.util.Slog;
 import android.view.contentcapture.ContentCaptureContext;
-import android.view.contentcapture.ContentCaptureSession;
 import android.view.contentcapture.ContentCaptureSessionId;
 
 import com.android.internal.annotations.GuardedBy;
@@ -38,7 +43,6 @@
 
     final IBinder mActivityToken;
     private final ContentCapturePerUserService mService;
-    private final RemoteContentCaptureService mRemoteService;
 
     // NOTE: this is the "internal" context (like package and taskId), not the explicit content
     // set by apps - those are only send to the ContentCaptureService.
@@ -61,15 +65,13 @@
     private final int mUid;
 
     ContentCaptureServerSession(@NonNull IBinder activityToken,
-            @NonNull ContentCapturePerUserService service,
-            @NonNull RemoteContentCaptureService remoteService,
-            @NonNull ComponentName appComponentName, @NonNull IResultReceiver sessionStateReceiver,
+            @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
+            @NonNull IResultReceiver sessionStateReceiver,
             int taskId, int displayId, @NonNull String sessionId, int uid, int flags) {
         mActivityToken = activityToken;
         mService = service;
         mId = Preconditions.checkNotNull(sessionId);
         mUid = uid;
-        mRemoteService = remoteService;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
                 appComponentName, taskId, displayId, flags);
         mSessionStateReceiver = sessionStateReceiver;
@@ -87,8 +89,12 @@
      */
     @GuardedBy("mLock")
     public void notifySessionStartedLocked(@NonNull IResultReceiver clientReceiver) {
-        mRemoteService.onSessionStarted(mContentCaptureContext, mId, mUid, clientReceiver,
-                ContentCaptureSession.STATE_ACTIVE);
+        if (mService.mRemoteService == null) {
+            Slog.w(TAG, "notifySessionStartedLocked(): no remote service");
+            return;
+        }
+        mService.mRemoteService.onSessionStarted(mContentCaptureContext, mId, mUid, clientReceiver,
+                STATE_ACTIVE);
     }
 
     /**
@@ -101,7 +107,11 @@
             logHistory.log("snapshot: id=" + mId);
         }
 
-        mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
+        if (mService.mRemoteService == null) {
+            Slog.w(TAG, "sendActivitySnapshotLocked(): no remote service");
+            return;
+        }
+        mService.mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
     }
 
     /**
@@ -134,7 +144,11 @@
         }
         // TODO(b/111276913): must call client to set session as FINISHED_BY_SERVER
         if (notifyRemoteService) {
-            mRemoteService.onSessionFinished(mId);
+            if (mService.mRemoteService == null) {
+                Slog.w(TAG, "destroyLocked(): no remote service");
+                return;
+            }
+            mService.mRemoteService.onSessionFinished(mId);
         }
     }
 
@@ -143,10 +157,27 @@
      */
     @GuardedBy("mLock")
     public void resurrectLocked() {
-        mRemoteService.onSessionStarted(new ContentCaptureContext(mContentCaptureContext,
+        final RemoteContentCaptureService remoteService = mService.mRemoteService;
+        if (remoteService == null) {
+            Slog.w(TAG, "destroyLocked(: no remote service");
+            return;
+        }
+        if (mService.isVerbose()) {
+            Slog.v(TAG, "resurrecting " + mActivityToken + " on " + remoteService);
+        }
+        remoteService.onSessionStarted(new ContentCaptureContext(mContentCaptureContext,
                 ContentCaptureContext.FLAG_RECONNECTED), mId, mUid, mSessionStateReceiver,
-                ContentCaptureSession.STATE_ACTIVE
-                        | ContentCaptureSession.STATE_SERVICE_RESURRECTED);
+                STATE_ACTIVE | STATE_SERVICE_RESURRECTED);
+    }
+
+    /**
+     * Called to pause the session while the service is being updated.
+     */
+    @GuardedBy("mLock")
+    public void pauseLocked() {
+        if (mService.isVerbose()) Slog.v(TAG, "pausing " + mActivityToken);
+        setClientState(mSessionStateReceiver, STATE_DISABLED | STATE_SERVICE_UPDATING,
+                /* binder= */ null);
     }
 
     @GuardedBy("mLock")
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 2ce5059..df9ccbc 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -54,7 +54,7 @@
         mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
 
         // Bind right away, which will trigger a onConnected() on service's
-        scheduleBind();
+        ensureBoundLocked();
     }
 
     @Override // from AbstractRemoteService
@@ -89,6 +89,10 @@
         }
     }
 
+    public void ensureBoundLocked() {
+        scheduleBind();
+    }
+
     /**
      * Called by {@link ContentCaptureServerSession} to generate a call to the
      * {@link RemoteContentCaptureService} to indicate the session was created.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ec5987e..21c1e12 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2564,7 +2564,12 @@
                                     || (nai.networkMisc.acceptPartialConnectivity
                                             && nai.partialConnectivity);
                     // Once a network is determined to have partial connectivity, it cannot
-                    // go back to full connectivity without a disconnect.
+                    // go back to full connectivity without a disconnect. This is because
+                    // NetworkMonitor can only communicate either PARTIAL_CONNECTIVITY or VALID,
+                    // but not both.
+                    // TODO: Provide multi-testResult to improve the communication between
+                    // ConnectivityService and NetworkMonitor, so that ConnectivityService could
+                    // know the real status of network.
                     final boolean partialConnectivityChanged =
                             (partialConnectivity && !nai.partialConnectivity);
 
@@ -3470,8 +3475,12 @@
         return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
-    @Override
-    public boolean getAvoidBadWifi() {
+    /**
+     * Return whether the device should maintain continuous, working connectivity by switching away
+     * from WiFi networks having no connectivity.
+     * @see MultinetworkPolicyTracker#getAvoidBadWifi()
+     */
+    public boolean shouldAvoidBadWifi() {
         if (!checkNetworkStackPermission()) {
             throw new SecurityException("avoidBadWifi requires NETWORK_STACK permission");
         }
@@ -3581,9 +3590,7 @@
         // NetworkMonitor detects the network is partial connectivity. Need to change the design to
         // popup the notification immediately when the network is partial connectivity.
         if (nai.partialConnectivity) {
-            // Treat PARTIAL_CONNECTIVITY as NO_INTERNET temporary until Settings has been updated.
-            // TODO: Need to change back to PARTIAL_CONNECTIVITY when Settings part is merged.
-            showNetworkNotification(nai, NotificationType.NO_INTERNET);
+            showNetworkNotification(nai, NotificationType.PARTIAL_CONNECTIVITY);
         } else {
             showNetworkNotification(nai, NotificationType.NO_INTERNET);
         }
diff --git a/services/core/java/com/android/server/DynamicAndroidService.java b/services/core/java/com/android/server/DynamicSystemService.java
similarity index 92%
rename from services/core/java/com/android/server/DynamicAndroidService.java
rename to services/core/java/com/android/server/DynamicSystemService.java
index b02bfb1..f5bd11c 100644
--- a/services/core/java/com/android/server/DynamicAndroidService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -22,25 +22,25 @@
 import android.gsi.IGsiService;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
-import android.os.IDynamicAndroidService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.image.IDynamicSystemService;
 import android.util.Slog;
 
 /**
- * DynamicAndroidService implements IDynamicAndroidService. It provides permission check before
+ * DynamicSystemService implements IDynamicSystemService. It provides permission check before
  * passing requests to gsid
  */
-public class DynamicAndroidService extends IDynamicAndroidService.Stub implements DeathRecipient {
-    private static final String TAG = "DynamicAndroidService";
+public class DynamicSystemService extends IDynamicSystemService.Stub implements DeathRecipient {
+    private static final String TAG = "DynamicSystemService";
     private static final String NO_SERVICE_ERROR = "no gsiservice";
     private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
 
     private Context mContext;
     private volatile IGsiService mGsiService;
 
-    DynamicAndroidService(Context context) {
+    DynamicSystemService(Context context) {
         mContext = context;
     }
 
@@ -93,9 +93,9 @@
 
     private void checkPermission() {
         if (mContext.checkCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+                        android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
                 != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires MANAGE_DYNAMIC_ANDROID permission");
+            throw new SecurityException("Requires MANAGE_DYNAMIC_SYSTEM permission");
         }
     }
 
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index b89223b..f0244c3 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -3597,10 +3597,18 @@
                 pw.println("    " + provider + ": " + location);
             }
 
-            mGeofenceManager.dump(pw);
-
-            pw.append("  ");
-            mBlacklist.dump(pw);
+            if (mGeofenceManager != null) {
+                mGeofenceManager.dump(pw);
+            } else {
+                pw.println("  Geofences: null");
+            }
+          
+            if (mBlacklist != null) {
+                pw.append("  ");
+                mBlacklist.dump(pw);
+            } else {
+                pw.println("  mBlacklist=null");
+            }
 
             if (mLocationControllerExtraPackage != null) {
                 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
@@ -3614,8 +3622,12 @@
                 }
             }
 
-            pw.append("  fudger: ");
-            mLocationFudger.dump(fd, pw, args);
+            if (mLocationFudger != null) {
+                pw.append("  fudger: ");
+                mLocationFudger.dump(fd, pw, args);
+            } else {
+                pw.println("  fudger: null");
+            }
 
             if (args.length > 0 && "short".equals(args[0])) {
                 return;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5bd0b89..05214824 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3862,6 +3862,14 @@
                         case "jp.naver.line.android": // b/124767356
                         case "com.mxtech.videoplayer.ad": // b/124531483
                         case "com.whatsapp": // b/124766614
+                        case "com.maxmpz.audioplayer": // b/127886230
+                        case "com.estrongs.android.pop": // b/127926473
+                        case "com.roidapp.photogrid": // b/128269119
+                        case "com.cleanmaster.mguard": // b/128384413
+                        case "com.skype.raider": // b/128487044
+                        case "org.telegram.messenger": // b/128652960
+                        case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
+                        case "ak.alizandro.smartaudiobookplayer": // b/129084042
                             return Zygote.MOUNT_EXTERNAL_LEGACY;
                     }
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 97cc756..a1f2ac6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5121,6 +5121,7 @@
                                 String data, Bundle extras, boolean ordered,
                                 boolean sticky, int sendingUser) {
                             synchronized (ActivityManagerService.this) {
+                                mOomAdjuster.mAppCompact.compactAllSystem();
                                 requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                             }
                         }
@@ -8614,6 +8615,10 @@
         synchronized (this) {
             final long now = SystemClock.uptimeMillis();
             final long timeSinceLastIdle = now - mLastIdleTime;
+
+            // Compact all non-zygote processes to freshen up the page cache.
+            mOomAdjuster.mAppCompact.compactAllSystem();
+
             final long lowRamSinceLastIdle = getLowRamTimeSinceIdle(now);
             mLastIdleTime = now;
             mLowRamTimeSinceLastIdle = 0;
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 9216343..f58fb95 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -51,6 +51,8 @@
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
     @VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
+    @VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5";
+    @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6";
     @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE =
             "compact_statsd_sample_rate";
 
@@ -73,6 +75,8 @@
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000;
     // The sampling rate to push app compaction events into statsd for upload.
     @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;
 
@@ -85,7 +89,10 @@
     // Handler constants.
     static final int COMPACT_PROCESS_SOME = 1;
     static final int COMPACT_PROCESS_FULL = 2;
+    static final int COMPACT_PROCESS_PERSISTENT = 3;
+    static final int COMPACT_PROCESS_BFGS = 4;
     static final int COMPACT_PROCESS_MSG = 1;
+    static final int COMPACT_SYSTEM_MSG = 2;
 
     /**
      * This thread must be moved to the system background cpuset.
@@ -142,6 +149,10 @@
     @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
     @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile long mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
+    @GuardedBy("mPhenotypeFlagLock")
     private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
 
     private final Random mRandom = new Random();
@@ -224,6 +235,46 @@
 
     }
 
+    @GuardedBy("mAm")
+    void compactAppPersistent(ProcessRecord app) {
+        app.reqCompactAction = COMPACT_PROCESS_PERSISTENT;
+        mPendingCompactionProcesses.add(app);
+        mCompactionHandler.sendMessage(
+                mCompactionHandler.obtainMessage(
+                    COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
+    }
+
+    @GuardedBy("mAm")
+    boolean shouldCompactPersistent(ProcessRecord app, long now) {
+        return (app.lastCompactTime == 0
+                || (now - app.lastCompactTime) > mCompactThrottlePersistent);
+    }
+
+    @GuardedBy("mAm")
+    void compactAppBfgs(ProcessRecord app) {
+        app.reqCompactAction = COMPACT_PROCESS_BFGS;
+        mPendingCompactionProcesses.add(app);
+        mCompactionHandler.sendMessage(
+                mCompactionHandler.obtainMessage(
+                    COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
+    }
+
+    @GuardedBy("mAm")
+    boolean shouldCompactBFGS(ProcessRecord app, long now) {
+        return (app.lastCompactTime == 0
+                || (now - app.lastCompactTime) > mCompactThrottleBFGS);
+    }
+
+    @GuardedBy("mAm")
+    void compactAllSystem() {
+        if (mUseCompaction) {
+            mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage(
+                                              COMPACT_SYSTEM_MSG));
+        }
+    }
+
+    private native void compactSystem();
+
     /**
      * Reads the flag value from DeviceConfig to determine whether app compaction
      * should be enabled, and starts/stops the compaction thread as needed.
@@ -265,10 +316,18 @@
         String throttleFullFullFlag =
                 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                     KEY_COMPACT_THROTTLE_4);
+        String throttleBFGSFlag =
+                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_COMPACT_THROTTLE_5);
+        String throttlePersistentFlag =
+                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_COMPACT_THROTTLE_6);
 
         if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag)
                 || TextUtils.isEmpty(throttleFullSomeFlag)
-                || TextUtils.isEmpty(throttleFullFullFlag)) {
+                || TextUtils.isEmpty(throttleFullFullFlag)
+                || TextUtils.isEmpty(throttleBFGSFlag)
+                || TextUtils.isEmpty(throttlePersistentFlag)) {
             // Set defaults for all if any are not set.
             useThrottleDefaults = true;
         } else {
@@ -277,6 +336,8 @@
                 mCompactThrottleSomeFull = Integer.parseInt(throttleSomeFullFlag);
                 mCompactThrottleFullSome = Integer.parseInt(throttleFullSomeFlag);
                 mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag);
+                mCompactThrottleBFGS = Integer.parseInt(throttleBFGSFlag);
+                mCompactThrottlePersistent = Integer.parseInt(throttlePersistentFlag);
             } catch (NumberFormatException e) {
                 useThrottleDefaults = true;
             }
@@ -287,6 +348,8 @@
             mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
             mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
             mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
+            mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5;
+            mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
         }
     }
 
@@ -332,14 +395,19 @@
                     synchronized (mAm) {
                         proc = mPendingCompactionProcesses.remove(0);
 
+                        pendingAction = proc.reqCompactAction;
+
                         // don't compact if the process has returned to perceptible
-                        if (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        // and this is only a cached/home/prev compaction
+                        if ((pendingAction == COMPACT_PROCESS_SOME
+                                || pendingAction == COMPACT_PROCESS_FULL)
+                                && (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) {
                             return;
                         }
 
                         pid = proc.pid;
                         name = proc.processName;
-                        pendingAction = proc.reqCompactAction;
+
                         lastCompactAction = proc.lastCompactAction;
                         lastCompactTime = proc.lastCompactTime;
                     }
@@ -356,31 +424,49 @@
                     // Note that we explicitly don't take mPhenotypeFlagLock here as the flags
                     // should very seldom change, and taking the risk of using the wrong action is
                     // preferable to taking the lock for every single compaction action.
-                    if (pendingAction == COMPACT_PROCESS_SOME) {
-                        if ((lastCompactAction == COMPACT_PROCESS_SOME
-                                  && (start - lastCompactTime < mCompactThrottleSomeSome))
-                                  || (lastCompactAction == COMPACT_PROCESS_FULL
-                                      && (start - lastCompactTime
-                                          < mCompactThrottleSomeFull))) {
-                            return;
-                        }
-                    } else {
-                        if ((lastCompactAction == COMPACT_PROCESS_SOME
-                                  && (start - lastCompactTime < mCompactThrottleFullSome))
-                                  || (lastCompactAction == COMPACT_PROCESS_FULL
-                                      && (start - lastCompactTime
-                                          < mCompactThrottleFullFull))) {
-                            return;
+                    if (lastCompactTime != 0) {
+                        if (pendingAction == COMPACT_PROCESS_SOME) {
+                            if ((lastCompactAction == COMPACT_PROCESS_SOME
+                                    && (start - lastCompactTime < mCompactThrottleSomeSome))
+                                    || (lastCompactAction == COMPACT_PROCESS_FULL
+                                        && (start - lastCompactTime
+                                                < mCompactThrottleSomeFull))) {
+                                return;
+                            }
+                        } else if (pendingAction == COMPACT_PROCESS_FULL) {
+                            if ((lastCompactAction == COMPACT_PROCESS_SOME
+                                    && (start - lastCompactTime < mCompactThrottleFullSome))
+                                    || (lastCompactAction == COMPACT_PROCESS_FULL
+                                        && (start - lastCompactTime
+                                                < mCompactThrottleFullFull))) {
+                                return;
+                            }
+                        } else if (pendingAction == COMPACT_PROCESS_PERSISTENT) {
+                            if (start - lastCompactTime < mCompactThrottlePersistent) {
+                                return;
+                            }
+                        } else if (pendingAction == COMPACT_PROCESS_BFGS) {
+                            if (start - lastCompactTime < mCompactThrottleBFGS) {
+                                return;
+                            }
                         }
                     }
-
-                    if (pendingAction == COMPACT_PROCESS_SOME) {
-                        action = mCompactActionSome;
-                    } else {
-                        action = mCompactActionFull;
+                    switch (pendingAction) {
+                        case COMPACT_PROCESS_SOME:
+                            action = mCompactActionSome;
+                            break;
+                        // For the time being, treat these as equivalent.
+                        case COMPACT_PROCESS_FULL:
+                        case COMPACT_PROCESS_PERSISTENT:
+                        case COMPACT_PROCESS_BFGS:
+                            action = mCompactActionFull;
+                            break;
+                        default:
+                            action = COMPACT_ACTION_NONE;
+                            break;
                     }
 
-                    if (action.equals(COMPACT_ACTION_NONE)) {
+                    if (COMPACT_ACTION_NONE.equals(action)) {
                         return;
                     }
 
@@ -422,6 +508,13 @@
                         // nothing to do, presumably the process died
                         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     }
+                    break;
+                }
+                case COMPACT_SYSTEM_MSG: {
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
+                    compactSystem();
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                    break;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 4d5cb8c..f86ba27 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -754,7 +754,7 @@
     }
 
     public void noteStartAudio(int uid) {
-        enforceCallingPermission();
+        enforceSelfOrCallingPermission(uid);
         synchronized (mStats) {
             mStats.noteAudioOnLocked(uid);
             StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
@@ -763,7 +763,7 @@
     }
 
     public void noteStopAudio(int uid) {
-        enforceCallingPermission();
+        enforceSelfOrCallingPermission(uid);
         synchronized (mStats) {
             mStats.noteAudioOffLocked(uid);
             StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
@@ -772,7 +772,7 @@
     }
 
     public void noteStartVideo(int uid) {
-        enforceCallingPermission();
+        enforceSelfOrCallingPermission(uid);
         synchronized (mStats) {
             mStats.noteVideoOnLocked(uid);
             StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null,
@@ -781,7 +781,7 @@
     }
 
     public void noteStopVideo(int uid) {
-        enforceCallingPermission();
+        enforceSelfOrCallingPermission(uid);
         synchronized (mStats) {
             mStats.noteVideoOffLocked(uid);
             StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
@@ -1182,6 +1182,13 @@
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
     }
 
+    private void enforceSelfOrCallingPermission(int uid) {
+        if (Binder.getCallingUid() == uid) {
+            return;
+        }
+        enforceCallingPermission();
+    }
+
     final class WakeupReasonThread extends Thread {
         private static final int MAX_REASON_SIZE = 512;
         private CharsetDecoder mDecoder;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index aa03de1..c1b9a20 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1686,9 +1686,10 @@
 
         int changes = 0;
 
-        if (app.curAdj != app.setAdj) {
-            // don't compact during bootup
-            if (mAppCompact.useCompaction() && mService.mBooted) {
+        // don't compact during bootup
+        if (mAppCompact.useCompaction() && mService.mBooted) {
+            // Cached and prev/home compaction
+            if (app.curAdj != app.setAdj) {
                 // Perform a minor compaction when a perceptible app becomes the prev/home app
                 // Perform a major compaction when any app enters cached
                 // reminder: here, setAdj is previous state, curAdj is upcoming state
@@ -1702,7 +1703,23 @@
                         && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
                     mAppCompact.compactAppFull(app);
                 }
+            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
+                    && app.setAdj < ProcessList.FOREGROUND_APP_ADJ
+                    // Because these can fire independent of oom_adj/procstate changes, we need
+                    // to throttle the actual dispatch of these requests in addition to the
+                    // processing of the requests. As a result, there is throttling both here
+                    // and in AppCompactor.
+                    && mAppCompact.shouldCompactPersistent(app, now)) {
+                mAppCompact.compactAppPersistent(app);
+            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
+                    && app.getCurProcState()
+                        == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+                    && mAppCompact.shouldCompactBFGS(app, now)) {
+                mAppCompact.compactAppBfgs(app);
             }
+        }
+
+        if (app.curAdj != app.setAdj) {
             ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
                 String msg = "Set " + app.pid + " " + app.processName + " adj "
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 10b67c1..2e5dd3b 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1257,6 +1257,7 @@
                 }
                 scheduleWriteLocked();
             }
+            uidState.evalForegroundOps(mOpModeWatchers);
         }
 
         String[] uidPackageNames = getPackagesForUid(uid);
@@ -2414,8 +2415,6 @@
     private void commitUidPendingStateLocked(UidState uidState) {
         final boolean lastForeground = uidState.state <= UID_STATE_MAX_LAST_NON_RESTRICTED;
         final boolean nowForeground = uidState.pendingState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
-        uidState.state = uidState.pendingState;
-        uidState.pendingStateCommitTime = 0;
         if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
             for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
                 if (!uidState.foregroundOps.valueAt(fgi)) {
@@ -2424,11 +2423,10 @@
                 final int code = uidState.foregroundOps.keyAt(fgi);
                 // For location ops we consider fg state only if the fg service
                 // is of location type, for all other ops any fg service will do.
-                final long resolvedLastRestrictedUidState = resolveFirstUnrestrictedUidState(code);
-                final boolean resolvedLastFg = uidState.state <= resolvedLastRestrictedUidState;
-                final boolean resolvedNowBg = uidState.pendingState
-                        <= resolvedLastRestrictedUidState;
-                if (resolvedLastFg == resolvedNowBg) {
+                final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
+                final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
+                final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
+                if (resolvedLastFg == resolvedNowFg) {
                     continue;
                 }
                 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
@@ -2460,6 +2458,8 @@
                 }
             }
         }
+        uidState.state = uidState.pendingState;
+        uidState.pendingStateCommitTime = 0;
     }
 
     private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index a8e99da..b447c53 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.attention;
 
 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+import static android.provider.Settings.System.ADAPTIVE_SLEEP;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -45,6 +46,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.service.attention.AttentionService.AttentionFailureCodes;
 import android.service.attention.IAttentionCallback;
@@ -253,6 +255,16 @@
         }
     }
 
+    /** Disables service dependants. */
+    private void disableSelf() {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @GuardedBy("mLock")
     private void freeIfInactiveLocked() {
         // If we are called here, it means someone used the API again - reset the timer then.
@@ -384,6 +396,11 @@
         public void cancelAttentionCheck(int requestCode) {
             AttentionManagerService.this.cancelAttentionCheck(requestCode);
         }
+
+        @Override
+        public void disableSelf() {
+            AttentionManagerService.this.disableSelf();
+        }
     }
 
     private static final class AttentionCheckCache {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 152f587..93f7831 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6313,8 +6313,8 @@
     // Audio policy management
     //==========================================================================================
     public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
-            boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController,
-            IMediaProjection projection) {
+            boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
+            boolean isVolumeController, IMediaProjection projection) {
         AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
 
         if (!isPolicyRegisterAllowed(policyConfig, projection)) {
@@ -6335,7 +6335,7 @@
                     return null;
                 }
                 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
-                        isFocusPolicy, isVolumeController);
+                        isFocusPolicy, isTestFocusPolicy, isVolumeController);
                 pcb.asBinder().linkToDeath(app, 0/*flags*/);
                 regId = app.getRegistrationId();
                 mAudioPolicies.put(pcb.asBinder(), app);
@@ -6753,9 +6753,11 @@
          */
         int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
         boolean mIsFocusPolicy = false;
+        boolean mIsTestFocusPolicy = false;
 
         AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
-                boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
+                boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
+                boolean isVolumeController) {
             super(config);
             setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
             mPolicyCallback = token;
@@ -6766,7 +6768,8 @@
                 // can only ever be true if there is a focus listener
                 if (isFocusPolicy) {
                     mIsFocusPolicy = true;
-                    mMediaFocusControl.setFocusPolicy(mPolicyCallback);
+                    mIsTestFocusPolicy = isTestFocusPolicy;
+                    mMediaFocusControl.setFocusPolicy(mPolicyCallback, mIsTestFocusPolicy);
                 }
             }
             if (mIsVolumeController) {
@@ -6794,7 +6797,7 @@
 
         void release() {
             if (mIsFocusPolicy) {
-                mMediaFocusControl.unsetFocusPolicy(mPolicyCallback);
+                mMediaFocusControl.unsetFocusPolicy(mPolicyCallback, mIsTestFocusPolicy);
             }
             if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
                 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index d028e88..1e58b45 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -17,6 +17,7 @@
 package com.android.server.audio;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.media.AudioAttributes;
@@ -458,7 +459,15 @@
         }
     }
 
-    private IAudioPolicyCallback mFocusPolicy = null;
+    /** The current audio focus policy */
+    @GuardedBy("mAudioFocusLock")
+    @Nullable private IAudioPolicyCallback mFocusPolicy = null;
+    /**
+     * The audio focus policy that was registered before a test focus policy was registered
+     * during a test
+     */
+    @GuardedBy("mAudioFocusLock")
+    @Nullable private IAudioPolicyCallback mPreviousFocusPolicy = 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
@@ -466,22 +475,30 @@
     private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy =
             new HashMap<String, FocusRequester>();
 
-    void setFocusPolicy(IAudioPolicyCallback policy) {
+    void setFocusPolicy(IAudioPolicyCallback policy, boolean isTestFocusPolicy) {
         if (policy == null) {
             return;
         }
         synchronized (mAudioFocusLock) {
+            if (isTestFocusPolicy) {
+                mPreviousFocusPolicy = mFocusPolicy;
+            }
             mFocusPolicy = policy;
         }
     }
 
-    void unsetFocusPolicy(IAudioPolicyCallback policy) {
+    void unsetFocusPolicy(IAudioPolicyCallback policy, boolean isTestFocusPolicy) {
         if (policy == null) {
             return;
         }
         synchronized (mAudioFocusLock) {
             if (mFocusPolicy == policy) {
-                mFocusPolicy = null;
+                if (isTestFocusPolicy) {
+                    // restore the focus policy that was there before the focus policy test started
+                    mFocusPolicy = mPreviousFocusPolicy;
+                } else {
+                    mFocusPolicy = null;
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 3e48445..c60dd6c 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -1251,8 +1251,6 @@
         if (getCurrentClient() instanceof InternalRemovalClient
                 || getCurrentClient() instanceof InternalEnumerateClient) {
             Slog.w(getTag(), "User switched while performing cleanup");
-            removeClient(getCurrentClient());
-            clearEnumerateState();
         }
         updateActiveGroup(userId, null);
         doTemplateCleanupForUser(userId);
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 4289a25..54a4ad4 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.broadcastradio;
 
-import android.annotation.NonNull;
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -26,14 +25,13 @@
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.RadioManager;
-import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 import com.android.server.broadcastradio.hal2.AnnouncementAggregator;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -45,16 +43,20 @@
 
     private final ServiceImpl mServiceImpl = new ServiceImpl();
 
-    private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1 =
-            new com.android.server.broadcastradio.hal1.BroadcastRadioService();
-    private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2 =
-            new com.android.server.broadcastradio.hal2.BroadcastRadioService();
+    private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1;
+    private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2;
 
     private final Object mLock = new Object();
-    private List<RadioManager.ModuleProperties> mModules = null;
+    private List<RadioManager.ModuleProperties> mV1Modules = null;
 
     public BroadcastRadioService(Context context) {
         super(context);
+
+        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService();
+        mV1Modules = mHal1.loadModules();
+        OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
+        mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
+                max.isPresent() ? max.getAsInt() + 1 : 0);
     }
 
     @Override
@@ -62,14 +64,6 @@
         publishBinderService(Context.RADIO_SERVICE, mServiceImpl);
     }
 
-    /**
-     * Finds next available index for newly loaded modules.
-     */
-    private static int getNextId(@NonNull List<RadioManager.ModuleProperties> modules) {
-        OptionalInt max = modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
-        return max.isPresent() ? max.getAsInt() + 1 : 0;
-    }
-
     private class ServiceImpl extends IRadioService.Stub {
         private void enforcePolicyAccess() {
             if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission(
@@ -81,14 +75,10 @@
         @Override
         public List<RadioManager.ModuleProperties> listModules() {
             enforcePolicyAccess();
-            synchronized (mLock) {
-                if (mModules != null) return mModules;
-
-                mModules = mHal1.loadModules();
-                mModules.addAll(mHal2.loadModules(getNextId(mModules)));
-
-                return mModules;
-            }
+            List<RadioManager.ModuleProperties> modules = new ArrayList<>();
+            modules.addAll(mV1Modules);
+            modules.addAll(mHal2.listModules());
+            return modules;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 954c001..b8810c8f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -18,20 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
 import android.hardware.radio.IAnnouncementListener;
 import android.hardware.radio.ICloseHandle;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.RadioManager;
-import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
 import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IHwBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
@@ -39,52 +41,104 @@
 public class BroadcastRadioService {
     private static final String TAG = "BcRadio2Srv";
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private int mNextModuleId = 0;
+
+    @GuardedBy("mLock")
+    private final Map<String, Integer> mServiceNameToModuleIdMap = new HashMap<>();
+
+    @GuardedBy("mLock")
     private final Map<Integer, RadioModule> mModules = new HashMap<>();
 
-    private static @NonNull List<String> listByInterface(@NonNull String fqName) {
+    private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() {
+        @Override
+        public void onRegistration(String fqName, String serviceName, boolean preexisting) {
+            Slog.v(TAG, "onRegistration(" + fqName + ", " + serviceName + ", " + preexisting + ")");
+            Integer moduleId;
+            synchronized (mLock) {
+                // If the service has been registered before, reuse its previous module ID.
+                moduleId = mServiceNameToModuleIdMap.get(serviceName);
+                boolean newService = false;
+                if (moduleId == null) {
+                    newService = true;
+                    moduleId = mNextModuleId;
+                }
+
+                RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName);
+                if (module == null) {
+                    return;
+                }
+                Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName
+                        + " (HAL 2.0)");
+                mModules.put(moduleId, module);
+
+                if (newService) {
+                    mServiceNameToModuleIdMap.put(serviceName, moduleId);
+                    mNextModuleId++;
+                }
+
+                try {
+                    module.getService().linkToDeath(mDeathRecipient, moduleId);
+                } catch (RemoteException ex) {
+                    // Service has already died, so remove its entry from mModules.
+                    mModules.remove(moduleId);
+                }
+            }
+        }
+    };
+
+    private DeathRecipient mDeathRecipient = new DeathRecipient() {
+        @Override
+        public void serviceDied(long cookie) {
+            Slog.v(TAG, "serviceDied(" + cookie + ")");
+            synchronized (mLock) {
+                int moduleId = (int) cookie;
+                mModules.remove(moduleId);
+
+                for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) {
+                    if (entry.getValue() == moduleId) {
+                        Slog.i(TAG, "service " + entry.getKey()
+                                + " died; removed RadioModule with ID " + moduleId);
+                        return;
+                    }
+                }
+            }
+        }
+    };
+
+    public BroadcastRadioService(int nextModuleId) {
+        mNextModuleId = nextModuleId;
         try {
             IServiceManager manager = IServiceManager.getService();
             if (manager == null) {
-                Slog.e(TAG, "Failed to get HIDL Service Manager");
-                return Collections.emptyList();
+                Slog.e(TAG, "failed to get HIDL Service Manager");
+                return;
             }
-
-            List<String> list = manager.listByInterface(fqName);
-            if (list == null) {
-                Slog.e(TAG, "Didn't get interface list from HIDL Service Manager");
-                return Collections.emptyList();
-            }
-            return list;
+            manager.registerForNotifications(IBroadcastRadio.kInterfaceName, "", mServiceListener);
         } catch (RemoteException ex) {
-            Slog.e(TAG, "Failed fetching interface list", ex);
-            return Collections.emptyList();
+            Slog.e(TAG, "failed to register for service notifications: ", ex);
         }
     }
 
-    public @NonNull Collection<RadioManager.ModuleProperties> loadModules(int idx) {
-        Slog.v(TAG, "loadModules(" + idx + ")");
-
-        for (String serviceName : listByInterface(IBroadcastRadio.kInterfaceName)) {
-            Slog.v(TAG, "checking service: " + serviceName);
-
-            RadioModule module = RadioModule.tryLoadingModule(idx, serviceName);
-            if (module != null) {
-                Slog.i(TAG, "loaded broadcast radio module " + idx + ": " +
-                        serviceName + " (HAL 2.0)");
-                mModules.put(idx++, module);
-            }
+    public @NonNull Collection<RadioManager.ModuleProperties> listModules() {
+        synchronized (mLock) {
+            return mModules.values().stream().map(module -> module.mProperties)
+                    .collect(Collectors.toList());
         }
-
-        return mModules.values().stream().map(module -> module.mProperties).
-                collect(Collectors.toList());
     }
 
     public boolean hasModule(int id) {
-        return mModules.containsKey(id);
+        synchronized (mLock) {
+            return mModules.containsKey(id);
+        }
     }
 
     public boolean hasAnyModules() {
-        return !mModules.isEmpty();
+        synchronized (mLock) {
+            return !mModules.isEmpty();
+        }
     }
 
     public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig,
@@ -95,7 +149,10 @@
             throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.x");
         }
 
-        RadioModule module = mModules.get(moduleId);
+        RadioModule module = null;
+        synchronized (mLock) {
+            module = mModules.get(moduleId);
+        }
         if (module == null) {
             throw new IllegalArgumentException("Invalid module ID");
         }
@@ -111,12 +168,14 @@
             @NonNull IAnnouncementListener listener) {
         AnnouncementAggregator aggregator = new AnnouncementAggregator(listener);
         boolean anySupported = false;
-        for (RadioModule module : mModules.values()) {
-            try {
-                aggregator.watchModule(module, enabledTypes);
-                anySupported = true;
-            } catch (UnsupportedOperationException ex) {
-                Slog.v(TAG, "Announcements not supported for this module", ex);
+        synchronized (mLock) {
+            for (RadioModule module : mModules.values()) {
+                try {
+                    aggregator.watchModule(module, enabledTypes);
+                    anySupported = true;
+                } catch (UnsupportedOperationException ex) {
+                    Slog.v(TAG, "Announcements not supported for this module", ex);
+                }
             }
         }
         if (!anySupported) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 816ba0b..832f8e1 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -20,8 +20,6 @@
 import android.annotation.Nullable;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.hardware.radio.ITuner;
-import android.hardware.radio.RadioManager;
 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
 import android.hardware.broadcastradio.V2_0.Announcement;
 import android.hardware.broadcastradio.V2_0.DabTableEntry;
@@ -30,13 +28,12 @@
 import android.hardware.broadcastradio.V2_0.ICloseHandle;
 import android.hardware.broadcastradio.V2_0.ITunerSession;
 import android.hardware.broadcastradio.V2_0.Result;
-import android.os.ParcelableException;
+import android.hardware.radio.RadioManager;
 import android.os.RemoteException;
 import android.util.MutableInt;
 import android.util.Slog;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
@@ -78,6 +75,10 @@
         }
     }
 
+    public @NonNull IBroadcastRadio getService() {
+        return mService;
+    }
+
     public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb)
             throws RemoteException {
         TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 32f34b8..3010324 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -37,7 +37,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.SensorManager;
@@ -1275,11 +1274,12 @@
         if (token == null) {
             return false;
         }
-        final GraphicBuffer gb = SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
-                token, new Rect(), 0 /* width */, 0 /* height */, false /* useIdentityTransform */,
-                0 /* rotation */);
+        final SurfaceControl.ScreenshotGraphicBuffer gb =
+                SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
+                        token, new Rect(), 0 /* width */, 0 /* height */,
+                        false /* useIdentityTransform */, 0 /* rotation */);
         try {
-            outSurface.attachAndQueueBuffer(gb);
+            outSurface.attachAndQueueBuffer(gb.getGraphicBuffer());
         } catch (RuntimeException e) {
             Slog.w(TAG, "Failed to take screenshot - " + e.getMessage());
         }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 430203d..ed894ee 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -131,14 +131,10 @@
     private final boolean mRefreshServiceOnPackageUpdate;
 
     /**
-     * Name of the service's package that was active but then was removed because its package
-     * update.
-     *
-     * <p>It's a temporary state set / used by the {@link PackageMonitor} implementation, but
-     * defined here so it can be dumped.
+     * Name of the service packages whose APK are being updated, keyed by user id.
      */
     @GuardedBy("mLock")
-    private String mLastActivePackageName;
+    private SparseArray<String> mUpdatingPackageNames;
 
     /**
      * Default constructor.
@@ -565,6 +561,20 @@
     }
 
     /**
+     * Called before the package that provides the service for the given user is being updated.
+     */
+    protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
+        if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
+    }
+
+    /**
+     * Called after the package that provides the service for the given user is being updated.
+     */
+    protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+        if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
+    }
+
+    /**
      * Called after the service is removed from the cache.
      */
     @SuppressWarnings("unused")
@@ -602,8 +612,10 @@
             final int size = mServicesCache.size();
             pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
             pw.print(" Verbose: "); pw.println(realVerbose);
-            pw.print(" Refresh on package update: "); pw.println(mRefreshServiceOnPackageUpdate);
-            pw.print(" Last active service on update: "); pw.println(mLastActivePackageName);
+            pw.print("Refresh on package update: "); pw.println(mRefreshServiceOnPackageUpdate);
+            if (mUpdatingPackageNames != null) {
+                pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
+            }
             if (mServiceNameResolver != null) {
                 pw.print(prefix); pw.print("Name resolver: ");
                 mServiceNameResolver.dumpShort(pw); pw.println();
@@ -644,39 +656,49 @@
         final PackageMonitor monitor = new PackageMonitor() {
 
             @Override
-            public void onPackageUpdateStarted(String packageName, int uid) {
+            public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
+                if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
+                final String activePackageName = getActiveServicePackageNameLocked();
+                if (!packageName.equals(activePackageName)) return;
+
+                final int userId = getChangingUserId();
                 synchronized (mLock) {
-                    final String activePackageName = getActiveServicePackageNameLocked();
-                    if (packageName.equals(activePackageName)) {
-                        final int userId = getChangingUserId();
-                        if (mRefreshServiceOnPackageUpdate) {
-                            if (debug) {
-                                Slog.d(mTag, "Removing service for user " + userId
-                                        + " because package " + activePackageName
-                                        + " is being updated");
-                            }
-                            mLastActivePackageName = activePackageName;
-                            removeCachedServiceLocked(userId);
-                        } else {
-                            if (debug) {
-                                Slog.d(mTag, "Holding service for user " + userId
-                                        + " while package " + activePackageName
-                                        + " is being updated");
-                            }
+                    if (mUpdatingPackageNames == null) {
+                        mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
+                    }
+                    mUpdatingPackageNames.put(userId, packageName);
+                    onServicePackageUpdatingLocked(userId);
+                    if (mRefreshServiceOnPackageUpdate) {
+                        if (debug) {
+                            Slog.d(mTag, "Removing service for user " + userId + " because package "
+                                    + activePackageName + " is being updated");
+                        }
+                        removeCachedServiceLocked(userId);
+                    } else {
+                        if (debug) {
+                            Slog.d(mTag, "Holding service for user " + userId + " while package "
+                                    + activePackageName + " is being updated");
                         }
                     }
                 }
             }
 
             @Override
-            public void onPackageUpdateFinished(String packageName, int uid) {
+            public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
+                if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
+                final int userId = getChangingUserId();
                 synchronized (mLock) {
-                    String activePackageName = getActiveServicePackageNameLocked();
-                    if (activePackageName == null) {
-                        activePackageName = mLastActivePackageName;
-                        mLastActivePackageName = null;
-                    }
-                    if (!packageName.equals(activePackageName)) {
+                    final String activePackageName = mUpdatingPackageNames == null ? null
+                            : mUpdatingPackageNames.get(userId);
+                    if (packageName.equals(activePackageName)) {
+                        if (mUpdatingPackageNames != null) {
+                            mUpdatingPackageNames.remove(userId);
+                            if (mUpdatingPackageNames.size() == 0) {
+                                mUpdatingPackageNames = null;
+                            }
+                        }
+                        onServicePackageUpdatedLocked(userId);
+                    } else {
                         handlePackageUpdateLocked(packageName);
                     }
                 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 293813a..3e134b2 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -21,6 +21,9 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
@@ -106,6 +109,7 @@
 import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.CredentialType;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.VerifyCredentialResponse;
 import com.android.server.LocalServices;
@@ -319,8 +323,8 @@
             }
             Arrays.fill(newPasswordChars, '\u0000');
             final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-            setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    managedUserPassword, quality, managedUserId);
+            setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD, managedUserPassword,
+                    quality, managedUserId, false);
             // We store a private credential for the managed user that's unlocked by the primary
             // account holder's credential. As such, the user will never be prompted to enter this
             // password directly, so we always store a password.
@@ -1082,13 +1086,12 @@
     }
 
     @Override
-    public boolean havePassword(int userId) throws RemoteException {
+    public boolean havePassword(int userId) {
         checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
-                long handle = getSyntheticPasswordHandleLocked(userId);
-                return mSpManager.getCredentialType(handle, userId) ==
-                        LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+                final long handle = getSyntheticPasswordHandleLocked(userId);
+                return mSpManager.getCredentialType(handle, userId) == CREDENTIAL_TYPE_PASSWORD;
             }
         }
         // Do we need a permissions check here?
@@ -1096,13 +1099,12 @@
     }
 
     @Override
-    public boolean havePattern(int userId) throws RemoteException {
+    public boolean havePattern(int userId) {
         checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
-                long handle = getSyntheticPasswordHandleLocked(userId);
-                return mSpManager.getCredentialType(handle, userId) ==
-                        LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+                final long handle = getSyntheticPasswordHandleLocked(userId);
+                return mSpManager.getCredentialType(handle, userId) == CREDENTIAL_TYPE_PATTERN;
             }
         }
         // Do we need a permissions check here?
@@ -1112,9 +1114,8 @@
     private boolean isUserSecure(int userId) {
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
-                long handle = getSyntheticPasswordHandleLocked(userId);
-                return mSpManager.getCredentialType(handle, userId) !=
-                        LockPatternUtils.CREDENTIAL_TYPE_NONE;
+                final long handle = getSyntheticPasswordHandleLocked(userId);
+                return mSpManager.getCredentialType(handle, userId) != CREDENTIAL_TYPE_NONE;
             }
         }
         return mStorage.hasCredential(userId);
@@ -1167,7 +1168,7 @@
             throws RemoteException {
         try {
             doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
-                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                    CREDENTIAL_TYPE_PASSWORD,
                     false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
                 | NoSuchAlgorithmException | NoSuchPaddingException
@@ -1299,14 +1300,16 @@
                     // We use cached work profile password computed before clearing the parent's
                     // credential, otherwise they get lost
                     if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
-                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+                        setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE,
                                 profilePasswordMap.get(managedUserId),
-                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
+                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
+                                false);
                     } else {
                         Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
                         // Supplying null here would lead to untrusted credential change
-                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
-                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
+                        setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE, null,
+                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
+                                true);
                     }
                     mStorage.removeChildProfileLock(managedUserId);
                     removeKeystoreProfileKey(managedUserId);
@@ -1329,8 +1332,8 @@
     // should call setLockCredentialInternal.
     @Override
     public void setLockCredential(byte[] credential, int type,
-            byte[] savedCredential, int requestedQuality, int userId)
-            throws RemoteException {
+            byte[] savedCredential, int requestedQuality, int userId,
+            boolean allowUntrustedChange) throws RemoteException {
 
         if (!mLockPatternUtils.hasSecureLockScreen()) {
             throw new UnsupportedOperationException(
@@ -1338,15 +1341,17 @@
         }
         checkWritePermission(userId);
         synchronized (mSeparateChallengeLock) {
-            setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
+            setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId,
+                    allowUntrustedChange);
             setSeparateProfileChallengeEnabledLocked(userId, true, null);
             notifyPasswordChanged(userId);
         }
         notifySeparateProfileChallengeChanged(userId);
     }
 
-    private void setLockCredentialInternal(byte[] credential, int credentialType,
-            byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
+    private void setLockCredentialInternal(byte[] credential, @CredentialType int credentialType,
+            byte[] savedCredential, int requestedQuality, int userId,
+            boolean allowUntrustedChange) throws RemoteException {
         // Normalize savedCredential and credential such that empty string is always represented
         // as null.
         if (savedCredential == null || savedCredential.length == 0) {
@@ -1358,12 +1363,12 @@
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
-                        requestedQuality, userId);
+                        requestedQuality, userId, allowUntrustedChange);
                 return;
             }
         }
 
-        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+        if (credentialType == CREDENTIAL_TYPE_NONE) {
             if (credential != null) {
                 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
             }
@@ -1373,7 +1378,7 @@
             setKeystorePassword(null, userId);
             fixateNewestUserKeyAuth(userId);
             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
-            notifyActivePasswordMetricsAvailable(null, userId);
+            notifyActivePasswordMetricsAvailable(CREDENTIAL_TYPE_NONE, null, userId);
             mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
             return;
         }
@@ -1409,7 +1414,7 @@
                 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
                         currentHandle.type, requestedQuality, userId);
                 spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
-                        requestedQuality, userId);
+                        requestedQuality, userId, allowUntrustedChange);
                 return;
             }
         }
@@ -1431,8 +1436,7 @@
                 userId);
         } else {
             throw new RemoteException("Failed to enroll " +
-                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
-                            : "pattern"));
+                    (credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
         }
     }
 
@@ -1688,7 +1692,7 @@
             return VerifyCredentialResponse.ERROR;
         }
 
-        boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
+        boolean shouldReEnrollBaseZero = storedHash.type == CREDENTIAL_TYPE_PATTERN
                 && storedHash.isBaseZeroPattern;
 
         byte[] credentialToVerify;
@@ -1705,7 +1709,7 @@
             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
             if (shouldReEnrollBaseZero) {
                 setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
-                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
+                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false);
             }
         }
 
@@ -1736,7 +1740,7 @@
         try {
             // Unlock work profile, and work profile with unified lock must use password only
             return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
-                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                    CREDENTIAL_TYPE_PASSWORD,
                     true,
                     challenge,
                     userId, null /* progressCallback */);
@@ -1773,14 +1777,14 @@
 
         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
             final byte[] hash;
-            if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
+            if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
                 hash = LockPatternUtils.patternToHash(
                         LockPatternUtils.byteArrayToPattern(credential));
             } else {
                 hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
             }
             if (Arrays.equals(hash, storedHash.hash)) {
-                if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
+                if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
                     unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
                 } else {
                     unlockKeystore(credential, userId);
@@ -1793,12 +1797,12 @@
 
                 // migrate credential to GateKeeper
                 setLockCredentialInternal(credential, storedHash.type, null,
-                        storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
+                        storedHash.type == CREDENTIAL_TYPE_PATTERN
                                 ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                                 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                                /* TODO(roosa): keep the same password quality */, userId);
+                                /* TODO(roosa): keep the same password quality */, userId, false);
                 if (!hasChallenge) {
-                    notifyActivePasswordMetricsAvailable(credential, userId);
+                    notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
                     // Use credentials to create recoverable keystore snapshot.
                     mRecoverableKeyStoreManager.lockScreenSecretAvailable(
                             storedHash.type, credential, userId);
@@ -1823,7 +1827,7 @@
             if (progressCallback != null) {
                 progressCallback.onCredentialVerified();
             }
-            notifyActivePasswordMetricsAvailable(credential, userId);
+            notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
             unlockKeystore(credential, userId);
 
             Slog.i(TAG, "Unlocking user " + userId + " with token length "
@@ -1835,13 +1839,13 @@
                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
                 trustManager.setDeviceLockedForUser(userId, false);
             }
-            int reEnrollQuality = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
+            int reEnrollQuality = storedHash.type == CREDENTIAL_TYPE_PATTERN
                     ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                     : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                     /* TODO(roosa): keep the same password quality */;
             if (shouldReEnroll) {
                 setLockCredentialInternal(credential, storedHash.type, credential,
-                        reEnrollQuality, userId);
+                        reEnrollQuality, userId, false);
             } else {
                 // Now that we've cleared of all required GK migration, let's do the final
                 // migration to synthetic password.
@@ -1871,18 +1875,14 @@
      * Call this method to notify DPMS regarding the latest password metric. This should be called
      * when the user is authenticating or when a new password is being set.
      */
-    private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) {
-        final PasswordMetrics metrics;
-        if (password == null) {
-            metrics = new PasswordMetrics();
-        } else {
-            metrics = PasswordMetrics.computeForPassword(password);
-            metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
-        }
+    private void notifyActivePasswordMetricsAvailable(
+            @CredentialType int credentialType, byte[] password, @UserIdInt int userId) {
+        final PasswordMetrics metrics =
+                PasswordMetrics.computeForCredential(credentialType, password);
 
         // Asynchronous to avoid dead lock
         mHandler.post(() -> {
-            DevicePolicyManager dpm = (DevicePolicyManager)
+            final DevicePolicyManager dpm = (DevicePolicyManager)
                     mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
             dpm.setActivePasswordState(metrics, userId);
         });
@@ -1935,7 +1935,7 @@
 
         try {
             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
-                if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+                if (checkCredential(password.getBytes(), CREDENTIAL_TYPE_PATTERN,
                         userId, null /* progressCallback */)
                                 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
                     return true;
@@ -1946,7 +1946,7 @@
 
         try {
             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
-                if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                if (checkCredential(password.getBytes(), CREDENTIAL_TYPE_PASSWORD,
                         userId, null /* progressCallback */)
                                 .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
                     return true;
@@ -2392,11 +2392,11 @@
         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
     }
 
-    private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int
-            credentialType, boolean hasChallenge, long challenge, int userId,
+    private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
+            @CredentialType int credentialType, boolean hasChallenge, long challenge, int userId,
             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
         if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
-        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+        if (credentialType == CREDENTIAL_TYPE_NONE) {
             userCredential = null;
         }
 
@@ -2444,7 +2444,7 @@
         }
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
-            notifyActivePasswordMetricsAvailable(userCredential, userId);
+            notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId);
             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
             // Reset lockout
             if (mInjector.hasBiometrics()) {
@@ -2491,8 +2491,9 @@
      * added back when new password is set in future.
      */
     @GuardedBy("mSpManager")
-    private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType,
-            AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
+    private long setLockCredentialWithAuthTokenLocked(byte[] credential,
+            @CredentialType int credentialType, AuthenticationToken auth, int requestedQuality,
+            int userId) throws RemoteException {
         if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
         long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
                 credential, credentialType, auth, requestedQuality, userId);
@@ -2534,7 +2535,7 @@
         setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
         synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
 
-        notifyActivePasswordMetricsAvailable(credential, userId);
+        notifyActivePasswordMetricsAvailable(credentialType, credential, userId);
 
         if (profilePasswords != null) {
             for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
@@ -2547,7 +2548,8 @@
 
     @GuardedBy("mSpManager")
     private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
-            byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
+            byte[] savedCredential, int requestedQuality, int userId,
+            boolean allowUntrustedChange) throws RemoteException {
         if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
         if (isManagedProfileWithUnifiedLock(userId)) {
             // get credential from keystore when managed profile has unified lock
@@ -2568,28 +2570,31 @@
         VerifyCredentialResponse response = authResult.gkResponse;
         AuthenticationToken auth = authResult.authToken;
 
-        // If existing credential is provided, then it must match.
+        // If existing credential is provided, the existing credential must match.
         if (savedCredential != null && auth == null) {
-            throw new RemoteException("Failed to enroll " +
-                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
-                            : "pattern"));
+            throw new IllegalStateException("Failed to enroll "
+                    + (credentialType == CREDENTIAL_TYPE_PASSWORD
+                    ? "password" : "pattern"));
         }
-
         boolean untrustedReset = false;
         if (auth != null) {
             onAuthTokenKnownForUser(userId, auth);
-        } else if (response != null
-                && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
+        } else if (response == null) {
+            throw new IllegalStateException("Password change failed.");
+        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
             // We are performing an untrusted credential change, by DevicePolicyManager or other
             // internal callers that don't provide the existing credential
             Slog.w(TAG, "Untrusted credential change invoked");
             // Try to get a cached auth token, so we can keep SP unchanged.
             auth = mSpCache.get(userId);
+            if (!allowUntrustedChange) {
+                throw new IllegalStateException("Untrusted credential change was invoked but it was"
+                        + " not allowed. This is likely a bug. Auth token is null: "
+                        + Boolean.toString(auth == null));
+            }
             untrustedReset = true;
-        } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
-            Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
-                    (response != null ? "rate limit exceeded" : "failed"));
-            return;
+        } else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
+            throw new IllegalStateException("Rate limit exceeded, so password was not changed.");
         }
 
         if (auth != null) {
@@ -2660,7 +2665,7 @@
             if (!isUserSecure(userId)) {
                 if (shouldMigrateToSyntheticPasswordLocked(userId)) {
                     auth = initializeSyntheticPasswordLocked(null, null,
-                            LockPatternUtils.CREDENTIAL_TYPE_NONE,
+                            CREDENTIAL_TYPE_NONE,
                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
                 } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
                     long pwdHandle = getSyntheticPasswordHandleLocked(userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 2ede384..f0e431e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -37,6 +37,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.CredentialType;
 import com.android.server.LocalServices;
 import com.android.server.PersistentDataBlockManagerInternal;
 
@@ -96,11 +97,12 @@
         static final int VERSION_LEGACY = 0;
         static final int VERSION_GATEKEEPER = 1;
 
-        private CredentialHash(byte[] hash, int type, int version) {
+        private CredentialHash(byte[] hash, @CredentialType int type, int version) {
             this(hash, type, version, false /* isBaseZeroPattern */);
         }
 
-        private CredentialHash(byte[] hash, int type, int version, boolean isBaseZeroPattern) {
+        private CredentialHash(
+                byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) {
             if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                 if (hash == null) {
                     throw new RuntimeException("Empty hash for CredentialHash");
@@ -134,7 +136,7 @@
         }
 
         byte[] hash;
-        int type;
+        @CredentialType int type;
         int version;
         boolean isBaseZeroPattern;
 
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3872523..1f1ba20 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -63,6 +63,7 @@
  */
 public final class MediaProjectionManagerService extends SystemService
         implements Watchdog.Monitor {
+    private static final boolean REQUIRE_FG_SERVICE_FOR_PROJECTION = false;
     private static final String TAG = "MediaProjectionManagerService";
 
     private final Object mLock = new Object(); // Protects the list of media projections
@@ -100,21 +101,23 @@
                 false /*allowIsolated*/);
         mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
                 MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
-        mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
-            @Override
-            public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
-            }
+        if (REQUIRE_FG_SERVICE_FOR_PROJECTION) {
+            mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
+                @Override
+                public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+                }
 
-            @Override
-            public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
-                MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
-                        serviceTypes);
-            }
+                @Override
+                public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+                    MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
+                            serviceTypes);
+                }
 
-            @Override
-            public void onProcessDied(int pid, int uid) {
-            }
-        });
+                @Override
+                public void onProcessDied(int pid, int uid) {
+                }
+            });
+        }
     }
 
     @Override
@@ -462,7 +465,8 @@
                     return;
                 }
 
-                if (targetSdkVersion >= Build.VERSION_CODES.Q
+                if (REQUIRE_FG_SERVICE_FOR_PROJECTION
+                        && targetSdkVersion >= Build.VERSION_CODES.Q
                         && !mActivityManagerInternal.hasRunningForegroundService(
                                 uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
                     throw new SecurityException("Media projections require a foreground service"
diff --git a/services/core/java/com/android/server/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS
new file mode 100644
index 0000000..7e7335d
--- /dev/null
+++ b/services/core/java/com/android/server/media/projection/OWNERS
@@ -0,0 +1 @@
+michaelwr@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ca3c826..e43fc1f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4106,9 +4106,11 @@
         if (r == null) {
             return;
         }
-        if (adjustment.getSignals() != null) {
-            Bundle.setDefusable(adjustment.getSignals(), true);
-            r.addAdjustment(adjustment);
+        if (mAssistants.isAdjustmentAllowed(adjustment.getKey())) {
+            if (adjustment.getSignals() != null) {
+                Bundle.setDefusable(adjustment.getSignals(), true);
+                r.addAdjustment(adjustment);
+            }
         }
     }
 
@@ -7313,6 +7315,12 @@
             }
         }
 
+        protected boolean isAdjustmentAllowed(String type) {
+            synchronized (mLock) {
+                return mAllowedAdjustments.contains(type);
+            }
+        }
+
         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index b0d2704..15ed063 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -83,6 +83,9 @@
         if (!Objects.equals(theTruth.overlayTarget, oldSettings.targetPackageName)) {
             return true;
         }
+        if (!Objects.equals(theTruth.targetOverlayableName, oldSettings.targetOverlayableName)) {
+            return true;
+        }
         if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
             return true;
         }
@@ -149,6 +152,7 @@
 
                 mSettings.init(overlayPackage.packageName, newUserId,
                         overlayPackage.overlayTarget,
+                        overlayPackage.targetOverlayableName,
                         overlayPackage.applicationInfo.getBaseCodePath(),
                         overlayPackage.isStaticOverlayPackage(),
                         overlayPackage.overlayPriority,
@@ -331,6 +335,7 @@
         }
 
         mSettings.init(packageName, userId, overlayPackage.overlayTarget,
+                overlayPackage.targetOverlayableName,
                 overlayPackage.applicationInfo.getBaseCodePath(),
                 overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
                 overlayPackage.overlayCategory);
@@ -395,7 +400,7 @@
                 if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
                     mListener.onOverlaysChanged(pkg.overlayTarget, userId);
                 }
-                mSettings.init(packageName, userId, pkg.overlayTarget,
+                mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
                         pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
                         pkg.overlayPriority, pkg.overlayCategory);
             }
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 2b4ec03..667dfa1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -65,12 +65,13 @@
     private final ArrayList<SettingsItem> mItems = new ArrayList<>();
 
     void init(@NonNull final String packageName, final int userId,
-            @NonNull final String targetPackageName, @NonNull final String baseCodePath,
-            boolean isStatic, int priority, String overlayCategory) {
+            @NonNull final String targetPackageName,  @Nullable final String targetOverlayableName,
+            @NonNull final String baseCodePath, boolean isStatic, int priority,
+            @Nullable String overlayCategory) {
         remove(packageName, userId);
         final SettingsItem item =
-                new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
-                        isStatic, priority, overlayCategory);
+                new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
+                        baseCodePath, isStatic, priority, overlayCategory);
         if (isStatic) {
             // All static overlays are always enabled.
             item.setEnabled(true);
@@ -302,16 +303,17 @@
             pw.println(item.mPackageName + ":" + item.getUserId() + " {");
             pw.increaseIndent();
 
-            pw.println("mPackageName.......: " + item.mPackageName);
-            pw.println("mUserId............: " + item.getUserId());
-            pw.println("mTargetPackageName.: " + item.getTargetPackageName());
-            pw.println("mBaseCodePath......: " + item.getBaseCodePath());
-            pw.println("mState.............: " + OverlayInfo.stateToString(item.getState()));
-            pw.println("mState.............: " + OverlayInfo.stateToString(item.getState()));
-            pw.println("mIsEnabled.........: " + item.isEnabled());
-            pw.println("mIsStatic..........: " + item.isStatic());
-            pw.println("mPriority..........: " + item.mPriority);
-            pw.println("mCategory..........: " + item.mCategory);
+            pw.println("mPackageName...........: " + item.mPackageName);
+            pw.println("mUserId................: " + item.getUserId());
+            pw.println("mTargetPackageName.....: " + item.getTargetPackageName());
+            pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName());
+            pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
+            pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
+            pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
+            pw.println("mIsEnabled.............: " + item.isEnabled());
+            pw.println("mIsStatic..............: " + item.isStatic());
+            pw.println("mPriority..............: " + item.mPriority);
+            pw.println("mCategory..............: " + item.mCategory);
 
             pw.decreaseIndent();
             pw.println("}");
@@ -335,6 +337,7 @@
         private static final String ATTR_PACKAGE_NAME = "packageName";
         private static final String ATTR_STATE = "state";
         private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName";
+        private static final String ATTR_TARGET_OVERLAYABLE_NAME = "targetOverlayableName";
         private static final String ATTR_IS_STATIC = "isStatic";
         private static final String ATTR_PRIORITY = "priority";
         private static final String ATTR_CATEGORY = "category";
@@ -387,6 +390,8 @@
             final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID);
             final String targetPackageName = XmlUtils.readStringAttribute(parser,
                     ATTR_TARGET_PACKAGE_NAME);
+            final String targetOverlayableName = XmlUtils.readStringAttribute(parser,
+                    ATTR_TARGET_OVERLAYABLE_NAME);
             final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH);
             final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE);
             final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
@@ -394,8 +399,8 @@
             final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
             final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
 
-            return new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
-                    state, isEnabled, isStatic, priority, category);
+            return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
+                    baseCodePath, state, isEnabled, isStatic, priority, category);
         }
 
         public static void persist(@NonNull final ArrayList<SettingsItem> table,
@@ -422,6 +427,8 @@
             XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.mPackageName);
             XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.mUserId);
             XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.mTargetPackageName);
+            XmlUtils.writeStringAttribute(xml, ATTR_TARGET_OVERLAYABLE_NAME,
+                    item.mTargetOverlayableName);
             XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
             XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
             XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
@@ -436,6 +443,7 @@
         private final int mUserId;
         private final String mPackageName;
         private final String mTargetPackageName;
+        private final String mTargetOverlayableName;
         private String mBaseCodePath;
         private @OverlayInfo.State int mState;
         private boolean mIsEnabled;
@@ -445,12 +453,14 @@
         private String mCategory;
 
         SettingsItem(@NonNull final String packageName, final int userId,
-                @NonNull final String targetPackageName, @NonNull final String baseCodePath,
+                @NonNull final String targetPackageName,
+                @Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
                 final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic,
-                final int priority, String category) {
+                final int priority,  @Nullable String category) {
             mPackageName = packageName;
             mUserId = userId;
             mTargetPackageName = targetPackageName;
+            mTargetOverlayableName = targetOverlayableName;
             mBaseCodePath = baseCodePath;
             mState = state;
             mIsEnabled = isEnabled || isStatic;
@@ -461,16 +471,21 @@
         }
 
         SettingsItem(@NonNull final String packageName, final int userId,
-                @NonNull final String targetPackageName, @NonNull final String baseCodePath,
-                final boolean isStatic, final int priority, String category) {
-            this(packageName, userId, targetPackageName, baseCodePath, OverlayInfo.STATE_UNKNOWN,
-                    false, isStatic, priority, category);
+                @NonNull final String targetPackageName,
+                @Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
+                final boolean isStatic, final int priority, @Nullable String category) {
+            this(packageName, userId, targetPackageName, targetOverlayableName, baseCodePath,
+                    OverlayInfo.STATE_UNKNOWN, false, isStatic, priority, category);
         }
 
         private String getTargetPackageName() {
             return mTargetPackageName;
         }
 
+        private String getTargetOverlayableName() {
+            return mTargetOverlayableName;
+        }
+
         private int getUserId() {
             return mUserId;
         }
@@ -520,7 +535,7 @@
 
         private boolean setCategory(String category) {
             if (!Objects.equals(mCategory, category)) {
-                mCategory = category.intern();
+                mCategory = (category == null) ? null : category.intern();
                 invalidateCache();
                 return true;
             }
@@ -529,8 +544,8 @@
 
         private OverlayInfo getOverlayInfo() {
             if (mCache == null) {
-                mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
-                        mState, mUserId, mPriority, mIsStatic);
+                mCache = new OverlayInfo(mPackageName, mTargetPackageName, mTargetOverlayableName,
+                        mCategory, mBaseCodePath, mState, mUserId, mPriority, mIsStatic);
             }
             return mCache;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ec2ff28..c17b6c8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4979,7 +4979,9 @@
                         PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId,
                         false  /* throwIfPermNotDeclared*/)
                 || mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES)
-                        == PERMISSION_GRANTED;
+                        == PERMISSION_GRANTED
+                || mContext.checkCallingOrSelfPermission(
+                        Manifest.permission.ACCESS_SHARED_LIBRARIES) == PERMISSION_GRANTED;
 
         synchronized (mPackages) {
             List<SharedLibraryInfo> result = null;
@@ -5029,6 +5031,76 @@
         }
     }
 
+    @Nullable
+    @Override
+    public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
+            @NonNull String packageName, int flags, @NonNull int userId) {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES,
+                "getDeclaredSharedLibraries");
+        int callingUid = Binder.getCallingUid();
+        mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "getDeclaredSharedLibraries");
+
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
+        if (!sUserManager.exists(userId)) {
+            return null;
+        }
+
+        if (getInstantAppPackageName(callingUid) != null) {
+            return null;
+        }
+
+        synchronized (mPackages) {
+            List<SharedLibraryInfo> result = null;
+
+            int libraryCount = mSharedLibraries.size();
+            for (int i = 0; i < libraryCount; i++) {
+                LongSparseArray<SharedLibraryInfo> versionedLibrary = mSharedLibraries.valueAt(i);
+                if (versionedLibrary == null) {
+                    continue;
+                }
+
+                int versionCount = versionedLibrary.size();
+                for (int j = 0; j < versionCount; j++) {
+                    SharedLibraryInfo libraryInfo = versionedLibrary.valueAt(j);
+
+                    VersionedPackage declaringPackage = libraryInfo.getDeclaringPackage();
+                    if (!Objects.equals(declaringPackage.getPackageName(), packageName)) {
+                        continue;
+                    }
+
+                    long identity = Binder.clearCallingIdentity();
+                    try {
+                        PackageInfo packageInfo = getPackageInfoVersioned(declaringPackage, flags
+                                | PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
+                        if (packageInfo == null) {
+                            continue;
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+
+                    SharedLibraryInfo resultLibraryInfo = new SharedLibraryInfo(
+                            libraryInfo.getPath(), libraryInfo.getPackageName(),
+                            libraryInfo.getAllCodePaths(), libraryInfo.getName(),
+                            libraryInfo.getLongVersion(), libraryInfo.getType(),
+                            libraryInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(
+                            libraryInfo, flags, userId), libraryInfo.getDependencies() == null
+                            ? null : new ArrayList<>(libraryInfo.getDependencies()));
+
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    result.add(resultLibraryInfo);
+                }
+            }
+
+            return result != null ? new ParceledListSlice<>(result) : null;
+        }
+    }
+
     @GuardedBy("mPackages")
     private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
             SharedLibraryInfo libInfo, int flags, int userId) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index e36ac23..40f2a2b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1552,13 +1552,13 @@
                     oldPermAreModernStorageModel = false;
                 }
 
-                boolean shouldBeRestricted;
+                boolean shouldBeHidden;
                 boolean shouldBeFixed;
                 boolean shouldBeGranted = false;
                 boolean shouldBeRevoked = false;
                 int userFlags = -1;
                 if (useLegacyStoragePermissionModel) {
-                    shouldBeRestricted = isModernStoragePermission;
+                    shouldBeHidden = isModernStoragePermission;
                     shouldBeFixed = isQApp || isModernStoragePermission;
 
                     if (shouldBeFixed) {
@@ -1576,7 +1576,7 @@
                         shouldBeRevoked = !shouldBeGranted;
                     }
                 } else {
-                    shouldBeRestricted = isLegacyStoragePermission;
+                    shouldBeHidden = isLegacyStoragePermission;
                     shouldBeFixed = isLegacyStoragePermission;
 
                     if (shouldBeFixed) {
@@ -1636,7 +1636,12 @@
 
                     changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), userId,
                             FLAG_PERMISSION_HIDDEN,
-                            shouldBeRestricted ? FLAG_PERMISSION_HIDDEN : 0);
+                            shouldBeHidden ? FLAG_PERMISSION_HIDDEN : 0);
+
+                    if (shouldBeHidden) {
+                        changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
+                                userId, FLAG_PERMISSION_REVIEW_REQUIRED, 0);
+                    }
                 }
 
                 if (changed) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5a32aa0..55af357 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5126,7 +5126,7 @@
 
         // Start home.
         mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
-                displayId, fromHomeKey);
+                displayId, true /* allowInstrumenting */, fromHomeKey);
     }
 
     /**
@@ -5214,13 +5214,15 @@
     private VibrationEffect getVibrationEffect(int effectId) {
         long[] pattern;
         switch (effectId) {
-            case HapticFeedbackConstants.CLOCK_TICK:
             case HapticFeedbackConstants.CONTEXT_CLICK:
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
             case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
                 if (!mHapticTextHandleEnabled) {
                     return null;
                 }
+                // fallthrough
+            case HapticFeedbackConstants.CLOCK_TICK:
+                return VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
             case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
             case HapticFeedbackConstants.ENTRY_BUMP:
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9b427f5..cfe11bf 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4489,8 +4489,7 @@
         }
 
         @Override // Binder call
-        public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
-                int disableThreshold) {
+        public boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER,
                     "updateDynamicPowerSavings");
             final long ident = Binder.clearCallingIdentity();
@@ -4503,7 +4502,7 @@
                     // abort updating if we weren't able to succeed on the threshold
                     success &= Settings.Global.putInt(resolver,
                             Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
-                            dynamicPowerSavingsEnabled ? 1 : 0);
+                            powerSaveHint ? 1 : 0);
                 }
                 return success;
             } finally {
@@ -4542,13 +4541,13 @@
         }
 
         @Override // Binder call
-        public int getPowerSaveMode() {
+        public int getPowerSaveModeTrigger() {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null);
             final long ident = Binder.clearCallingIdentity();
             try {
                 return Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
-                        PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+                        Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+                        PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 61daca7..fe0b9a6 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -45,6 +45,7 @@
 import com.android.server.power.BatterySaverStateMachineProto;
 
 import java.io.PrintWriter;
+import java.text.NumberFormat;
 
 /**
  * Decides when to enable / disable battery saver.
@@ -188,7 +189,7 @@
     @GuardedBy("mLock")
     private int mSettingBatterySaverTriggerThreshold;
 
-    /** Previously known value of Settings.Global.AUTOMATIC_POWER_SAVER_MODE. */
+    /** Previously known value of Settings.Global.AUTOMATIC_POWER_SAVE_MODE. */
     @GuardedBy("mLock")
     private int mSettingAutomaticBatterySaver;
 
@@ -248,7 +249,7 @@
 
     /** @return true if the automatic percentage based mode should be used */
     private boolean isAutomaticModeActiveLocked() {
-        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE
                 && mSettingBatterySaverTriggerThreshold > 0;
     }
 
@@ -264,7 +265,7 @@
 
     /** @return true if the dynamic mode should be used */
     private boolean isDynamicModeActiveLocked() {
-        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC
                 && mDynamicPowerSavingsBatterySaver;
     }
 
@@ -304,7 +305,7 @@
                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOMATIC_POWER_SAVER_MODE),
+                    Settings.Global.AUTOMATIC_POWER_SAVE_MODE),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED),
@@ -367,8 +368,8 @@
         final int lowPowerModeTriggerLevel = getGlobalSetting(
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
         final int automaticBatterySaverMode = getGlobalSetting(
-                Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
-                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+                Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
         final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
                 Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                 mDynamicPowerSavingsDefaultDisableThreshold);
@@ -791,7 +792,7 @@
 
         manager.notify(DYNAMIC_MODE_NOTIFICATION_ID,
                 buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
-                        R.string.dynamic_mode_notification_title,
+                        mContext.getResources().getString(R.string.dynamic_mode_notification_title),
                         R.string.dynamic_mode_notification_summary,
                         Intent.ACTION_POWER_USAGE_SUMMARY));
     }
@@ -801,10 +802,13 @@
         ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
                 R.string.battery_saver_notification_channel_name);
 
+        final String percentage = NumberFormat.getPercentInstance()
+                .format((double) mBatteryLevel / 100.0);
         manager.notify(STICKY_AUTO_DISABLED_NOTIFICATION_ID,
                 buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID,
-                        R.string.battery_saver_sticky_disabled_notification_title,
-                        R.string.battery_saver_sticky_disabled_notification_summary,
+                        mContext.getResources().getString(
+                                R.string.battery_saver_charged_notification_title, percentage),
+                        R.string.battery_saver_off_notification_summary,
                         Settings.ACTION_BATTERY_SAVER_SETTINGS));
     }
 
@@ -816,7 +820,7 @@
         manager.createNotificationChannel(channel);
     }
 
-    private Notification buildNotification(@NonNull String channelId, @StringRes int titleId,
+    private Notification buildNotification(@NonNull String channelId, @NonNull String title,
             @StringRes int summaryId, @NonNull String intentAction) {
         Resources res = mContext.getResources();
         Intent intent = new Intent(intentAction);
@@ -827,11 +831,12 @@
 
         return new Notification.Builder(mContext, channelId)
                 .setSmallIcon(R.drawable.ic_battery)
-                .setContentTitle(res.getString(titleId))
+                .setContentTitle(title)
                 .setContentText(summary)
                 .setContentIntent(batterySaverIntent)
                 .setStyle(new Notification.BigTextStyle().bigText(summary))
                 .setOnlyAlertOnce(true)
+                .setAutoCancel(true)
                 .build();
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index b262a00..fc7646f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -364,7 +364,7 @@
      *  - Use the secondary home defined in the config.
      */
     public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId,
-            boolean fromHomeKey);
+            boolean allowInstrumenting, boolean fromHomeKey);
     /** Start home activities on all displays that support system decorations. */
     public abstract boolean startHomeOnAllDisplays(int userId, String reason);
     /** @return true if the given process is the factory test process. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c91ee8e..b8e6b0c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6492,10 +6492,10 @@
 
         @Override
         public boolean startHomeOnDisplay(int userId, String reason, int displayId,
-                boolean fromHomeKey) {
+                boolean allowInstrumenting, boolean fromHomeKey) {
             synchronized (mGlobalLock) {
                 return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
-                        fromHomeKey);
+                        allowInstrumenting, fromHomeKey);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ff4e256..6605f3c6 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -334,6 +334,11 @@
     private int mForcingShowNavBarLayer;
     private boolean mForceShowSystemBars;
 
+    /**
+     * Force the display of system bars regardless of other settings.
+     */
+    private boolean mForceShowSystemBarsFromExternal;
+
     private boolean mShowingDream;
     private boolean mLastShowingDream;
     private boolean mDreamingLockscreen;
@@ -409,6 +414,7 @@
         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
         mTranslucentDecorEnabled = r.getBoolean(R.bool.config_enableTranslucentDecor);
+        mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
         updateConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
@@ -613,6 +619,13 @@
         return mDockMode;
     }
 
+    /**
+     * @see WindowManagerService.setForceShowSystemBars
+     */
+    void setForceShowSystemBars(boolean forceShowSystemBars) {
+        mForceShowSystemBarsFromExternal = forceShowSystemBars;
+    }
+
     public boolean hasNavigationBar() {
         return mHasNavigationBar;
     }
@@ -1119,9 +1132,9 @@
     }
 
     /**
-     * @return true if the navigation bar is forced to stay visible
+     * @return true if the system bars are forced to stay visible
      */
-    public boolean isNavBarForcedShownLw(WindowState windowState) {
+    public boolean areSystemBarsForcedShownLw(WindowState windowState) {
         return mForceShowSystemBars;
     }
 
@@ -1141,8 +1154,8 @@
      *                        current visibility. Expressed as positive insets.
      * @param outOutsets The areas that are not real display, but we would like to treat as such.
      * @param outDisplayCutout The area that has been cut away from the display.
-     * @return Whether to always consume the navigation bar.
-     *         See {@link #isNavBarForcedShownLw(WindowState)}.
+     * @return Whether to always consume the system bars.
+     *         See {@link #areSystemBarsForcedShownLw(WindowState)}.
      */
     public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
             DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
@@ -3048,7 +3061,8 @@
         // We need to force system bars when the docked stack is visible, when the freeform stack
         // is visible but also when we are resizing for the transitions when docked stack
         // visibility changes.
-        mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
+        mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
+                || mForceShowSystemBarsFromExternal;
         final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
 
         // apply translucent bar vis flags
@@ -3420,6 +3434,8 @@
         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
         pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
+        pw.print(" mForceShowSystemBarsFromExternal=");
+        pw.println(mForceShowSystemBarsFromExternal);
         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
         mStatusBarController.dump(pw, prefix);
         mNavigationBarController.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 72a1a2f..432d75e 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -95,13 +95,15 @@
     }
 
     /**
-     * @return {@code true} if 1) Keyguard is showing, not going away, and not being occluded on the
-     *         given display, or 2) AOD is showing, {@code false} otherwise.
+     * @return {@code true} for default display when AOD is showing. Otherwise, same as
+     *         {@link #isKeyguardOrAodShowing(int)}
      * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
      */
     boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
-        return (mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId))
-                || mAodShowing;
+        if (displayId == DEFAULT_DISPLAY && mAodShowing) {
+            return true;
+        }
+        return isKeyguardOrAodShowing(displayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index d69ae3d..24b0213 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -845,6 +845,11 @@
         return mService.mAmInternal.getCurrentProfileIds();
     }
 
+    @VisibleForTesting
+    boolean isUserRunning(int userId, int flags) {
+        return mService.mAmInternal.isUserRunning(userId, flags);
+    }
+
     /**
      * @return the list of recent tasks for presentation.
      */
@@ -861,7 +866,7 @@
             boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
         final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
 
-        if (!mService.mAmInternal.isUserRunning(userId, FLAG_AND_UNLOCKED)) {
+        if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
             Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
             return new ArrayList<>();
         }
@@ -881,7 +886,7 @@
 
             if (isVisibleRecentTask(tr)) {
                 numVisibleTasks++;
-                if (isInVisibleRange(tr, numVisibleTasks)) {
+                if (isInVisibleRange(tr, numVisibleTasks, withExcluded)) {
                     // Fall through
                 } else {
                     // Not in visible range
@@ -908,51 +913,43 @@
                 continue;
             }
 
-            // Return the entry if desired by the caller.  We always return
-            // the first entry, because callers always expect this to be the
-            // foreground app.  We may filter others if the caller has
-            // not supplied RECENT_WITH_EXCLUDED and there is some reason
-            // we should exclude the entry.
-
-            if (i == 0
-                    || withExcluded
-                    || (tr.intent == null)
-                    || ((tr.intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                    == 0)) {
-                if (!getTasksAllowed) {
-                    // If the caller doesn't have the GET_TASKS permission, then only
-                    // allow them to see a small subset of tasks -- their own and home.
-                    if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
-                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
-                        continue;
-                    }
-                }
-                if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
-                    // Don't include auto remove tasks that are finished or finishing.
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "Skipping, auto-remove without activity: " + tr);
+            if (!getTasksAllowed) {
+                // If the caller doesn't have the GET_TASKS permission, then only
+                // allow them to see a small subset of tasks -- their own and home.
+                if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
                     continue;
                 }
-                if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "Skipping, unavail real act: " + tr);
-                    continue;
-                }
-
-                if (!tr.mUserSetupComplete) {
-                    // Don't include task launched while user is not done setting-up.
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "Skipping, user setup not complete: " + tr);
-                    continue;
-                }
-
-                final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
-                if (!getDetailedTasks) {
-                    rti.baseIntent.replaceExtras((Bundle)null);
-                }
-
-                res.add(rti);
             }
+
+            if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
+                // Don't include auto remove tasks that are finished or finishing.
+                if (DEBUG_RECENTS) {
+                    Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + tr);
+                }
+                continue;
+            }
+            if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
+                if (DEBUG_RECENTS) {
+                    Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + tr);
+                }
+                continue;
+            }
+
+            if (!tr.mUserSetupComplete) {
+                // Don't include task launched while user is not done setting-up.
+                if (DEBUG_RECENTS) {
+                    Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + tr);
+                }
+                continue;
+            }
+
+            final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
+            if (!getDetailedTasks) {
+                rti.baseIntent.replaceExtras((Bundle) null);
+            }
+
+            res.add(rti);
         }
         return res;
     }
@@ -994,7 +991,7 @@
             final TaskRecord tr = mTasks.get(i);
             if (isVisibleRecentTask(tr)) {
                 numVisibleTasks++;
-                if (isInVisibleRange(tr, numVisibleTasks)) {
+                if (isInVisibleRange(tr, numVisibleTasks, false /* skipExcludedCheck */)) {
                     res.put(tr.taskId, true);
                 }
             }
@@ -1215,7 +1212,8 @@
                     continue;
                 } else {
                     numVisibleTasks++;
-                    if (isInVisibleRange(task, numVisibleTasks) || !isTrimmable(task)) {
+                    if (isInVisibleRange(task, numVisibleTasks, false /* skipExcludedCheck */)
+                            || !isTrimmable(task)) {
                         // Keep visible tasks in range
                         i++;
                         continue;
@@ -1329,14 +1327,17 @@
     /**
      * @return whether the given visible task is within the policy range.
      */
-    private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks) {
-        // Keep the last most task even if it is excluded from recents
-        final boolean isExcludeFromRecents =
-                (task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                        == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
-        if (isExcludeFromRecents) {
-            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
-            return numVisibleTasks == 1;
+    private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks,
+            boolean skipExcludedCheck) {
+        if (!skipExcludedCheck) {
+            // Keep the most recent task even if it is excluded from recents
+            final boolean isExcludeFromRecents =
+                    (task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                            == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+            if (isExcludeFromRecents) {
+                if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
+                return numVisibleTasks == 1;
+            }
         }
 
         if (mMinNumVisibleTasks >= 0 && numVisibleTasks <= mMinNumVisibleTasks) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 26df832..3813669 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -208,7 +208,10 @@
             try {
                 synchronized (mService.getWindowManagerLock()) {
                     for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
-                        mPendingAnimations.get(i).mTask.setCanAffectSystemUiFlags(behindSystemBars);
+                        final Task task = mPendingAnimations.get(i).mTask;
+                        if (task.getActivityType() != mTargetActivityType) {
+                            task.setCanAffectSystemUiFlags(behindSystemBars);
+                        }
                     }
                     mService.mWindowPlacerLocked.requestTraversal();
                 }
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 24cf7f1..46b5f3a 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -347,7 +347,8 @@
     }
 
     boolean startHomeOnDisplay(int userId, String reason, int displayId) {
-        return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/);
+        return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
+                false /* fromHomeKey */);
     }
 
     /**
@@ -361,7 +362,8 @@
      *    If there are multiple activities matched, use first one.
      *  - Use the secondary home defined in the config.
      */
-    boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) {
+    boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
+            boolean fromHomeKey) {
         // Fallback to top focused display if the displayId is invalid.
         if (displayId == INVALID_DISPLAY) {
             displayId = getTopDisplayFocusedStack().mDisplayId;
@@ -383,7 +385,7 @@
             return false;
         }
 
-        if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
+        if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index e0d85e8..4379b7c 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -41,7 +41,7 @@
         return new TaskScreenshotAnimatable(task, getBufferFromTask(task));
     }
 
-    private static GraphicBuffer getBufferFromTask(Task task) {
+    private static SurfaceControl.ScreenshotGraphicBuffer getBufferFromTask(Task task) {
         if (task == null) {
             return null;
         }
@@ -51,7 +51,10 @@
                 task.getSurfaceControl().getHandle(), tmpRect, 1f);
     }
 
-    private TaskScreenshotAnimatable(Task task, GraphicBuffer buffer) {
+    private TaskScreenshotAnimatable(Task task,
+            SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) {
+        GraphicBuffer buffer = screenshotBuffer == null
+                ? null : screenshotBuffer.getGraphicBuffer();
         mTask = task;
         mWidth = (buffer != null) ? buffer.getWidth() : 1;
         mHeight = (buffer != null) ? buffer.getHeight() : 1;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index beb3d82..6fe8b43 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -279,8 +279,11 @@
             Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
             return null;
         }
-        final GraphicBuffer buffer = SurfaceControl.captureLayers(
-                task.getSurfaceControl().getHandle(), mTmpRect, scaleFraction);
+        final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
+                SurfaceControl.captureLayers(
+                        task.getSurfaceControl().getHandle(), mTmpRect, scaleFraction);
+        final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
+                : null;
         if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
             if (DEBUG_SCREENSHOT) {
                 Slog.w(TAG_WM, "Failed to take screenshot for " + task);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 938c8b4..dafed9e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -454,7 +454,7 @@
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
                 Rect stableInsets, Rect outsets, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-                boolean alwaysConsumeNavBar, int displayId,
+                boolean alwaysConsumeSystemBars, int displayId,
                 DisplayCutout.ParcelableWrapper displayCutout) {
             if (mergedConfiguration != null && mOuter != null
                     && mOuter.mOrientationOnCreation
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index dddc6b7..166a33d 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -34,8 +34,6 @@
 import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
 
 import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 import android.os.Bundle;
@@ -738,17 +736,16 @@
         final Rect bounds = wallpaperWindowState.getBounds();
         bounds.offsetTo(0, 0);
 
-        GraphicBuffer wallpaperBuffer = SurfaceControl.captureLayers(
+        SurfaceControl.ScreenshotGraphicBuffer wallpaperBuffer = SurfaceControl.captureLayers(
                 wallpaperWindowState.getSurfaceControl().getHandle(), bounds, 1 /* frameScale */);
 
         if (wallpaperBuffer == null) {
             Slog.w(TAG_WM, "Failed to screenshot wallpaper");
             return null;
         }
-        // TODO(b/116112787) Now that hardware bitmap creation can take color space, we
-        // should continue to fix screenshot.
-        return Bitmap.wrapHardwareBuffer(HardwareBuffer.createFromGraphicBuffer(wallpaperBuffer),
-                                         ColorSpace.get(ColorSpace.Named.SRGB));
+        return Bitmap.wrapHardwareBuffer(
+                HardwareBuffer.createFromGraphicBuffer(wallpaperBuffer.getGraphicBuffer()),
+                wallpaperBuffer.getColorSpace());
     }
 
     private WindowState getTopVisibleWallpaper() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7751560..4aa844f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1534,7 +1534,7 @@
             }
             if (displayPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack,
                     outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
-                res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
+                res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
             }
             outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win));
 
@@ -2206,8 +2206,8 @@
                 winAnimator.mReportSurfaceResized = false;
                 result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
             }
-            if (displayPolicy.isNavBarForcedShownLw(win)) {
-                result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR;
+            if (displayPolicy.areSystemBarsForcedShownLw(win)) {
+                result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
             }
             if (!win.isGoneForLayoutLw()) {
                 win.mResizedWhileGone = false;
@@ -5638,6 +5638,19 @@
         }
     }
 
+    @Override
+    public void setForceShowSystemBars(boolean show) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold permission "
+                    + android.Manifest.permission.STATUS_BAR);
+        }
+        synchronized (mGlobalLock) {
+            mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+                    DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show));
+        }
+    }
+
     public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
                 != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 600178f..6a21327 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3117,7 +3117,7 @@
 
         mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
                 reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
-                getDisplayContent().getDisplayPolicy().isNavBarForcedShownLw(this), displayId,
+                getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this), displayId,
                 new DisplayCutout.ParcelableWrapper(displayCutout));
         mDragResizingChangeReported = true;
     }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 00b815a..a7423ea 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -50,6 +50,7 @@
         "com_android_server_VibratorService.cpp",
         "com_android_server_PersistentDataBlockService.cpp",
         "com_android_server_GraphicsStatsService.cpp",
+        "com_android_server_am_AppCompactor.cpp",
         "onload.cpp",
     ],
 
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 63dca62..d5fbd2b 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -96,7 +96,7 @@
     }
     R val = static_cast<R>(effect);
     auto iter = hardware::hidl_enum_range<R>();
-    return val >= *iter.begin() && val < *std::prev(iter.end());
+    return val >= *iter.begin() && val <= *std::prev(iter.end());
 }
 
 static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
@@ -170,6 +170,9 @@
     } else if (isValidEffect<V1_2::Effect>(effect)) {
         ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
                            effectStrength, callback);
+    } else if (isValidEffect<V1_3::Effect>(effect)) {
+        ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
+                           effectStrength, callback);
     } else {
         ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                 static_cast<int32_t>(effect));
diff --git a/services/core/jni/com_android_server_am_AppCompactor.cpp b/services/core/jni/com_android_server_am_AppCompactor.cpp
new file mode 100644
index 0000000..de6aa8b
--- /dev/null
+++ b/services/core/jni/com_android_server_am_AppCompactor.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_TAG "AppCompactor"
+//#define LOG_NDEBUG 0
+
+#include <dirent.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/file.h>
+
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+
+namespace android {
+
+// This performs per-process reclaim on all processes belonging to non-app UIDs.
+// For the most part, these are non-zygote processes like Treble HALs, but it
+// also includes zygote-derived processes that run in system UIDs, like bluetooth
+// or potentially some mainline modules. The only process that should definitely
+// not be compacted is system_server, since compacting system_server around the
+// time of BOOT_COMPLETE could result in perceptible issues.
+static void com_android_server_am_AppCompactor_compactSystem(JNIEnv *, jobject) {
+    std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+    struct dirent* current;
+    while ((current = readdir(proc.get()))) {
+        if (current->d_type != DT_DIR) {
+            continue;
+        }
+
+        // don't compact system_server, rely on persistent compaction during screen off
+        // in order to avoid mmap_sem-related stalls
+        if (atoi(current->d_name) == getpid()) {
+            continue;
+        }
+
+        std::string status_name = StringPrintf("/proc/%s/status", current->d_name);
+        struct stat status_info;
+
+        if (stat(status_name.c_str(), &status_info) != 0) {
+            // must be some other directory that isn't a pid
+            continue;
+        }
+
+        // android.os.Process.FIRST_APPLICATION_UID
+        if (status_info.st_uid >= 10000) {
+            continue;
+        }
+
+        std::string reclaim_path = StringPrintf("/proc/%s/reclaim", current->d_name);
+        WriteStringToFile(std::string("all"), reclaim_path);
+    }
+}
+
+static const JNINativeMethod sMethods[] = {
+    /* name, signature, funcPtr */
+    {"compactSystem", "()V", (void*)com_android_server_am_AppCompactor_compactSystem},
+};
+
+int register_android_server_am_AppCompactor(JNIEnv* env)
+{
+    return jniRegisterNativeMethods(env, "com/android/server/am/AppCompactor",
+                                    sMethods, NELEM(sMethods));
+}
+
+}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 65a7eec..7df7ef3 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -998,8 +998,9 @@
     template<class T>
     size_t getMeasurementCount(const T& data);
 
-    jobject translateGnssClock(
-            JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock);
+    template<class T>
+    void translateGnssClock(JavaObject& object, const T& data);
+
     void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray);
 };
 
@@ -1025,12 +1026,12 @@
 void GnssMeasurementCallback::translateAndSetGnssData(const T& data) {
     JNIEnv* env = getJniEnv();
 
-    jobject clock;
-    jobjectArray measurementArray;
+    JavaObject gnssClockJavaObject(env, "android/location/GnssClock");
+    translateGnssClock(gnssClockJavaObject, data);
+    jobject clock = gnssClockJavaObject.get();
 
-    clock = translateGnssClock(env, &data.clock);
     size_t count = getMeasurementCount(data);
-    measurementArray = translateAllGnssMeasurements(env, data.measurements.data(), count);
+    jobjectArray measurementArray = translateAllGnssMeasurements(env, data.measurements.data(), count);
     setMeasurementData(env, clock, measurementArray);
 
     env->DeleteLocalRef(clock);
@@ -1124,43 +1125,59 @@
     SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation));
 }
 
-jobject GnssMeasurementCallback::translateGnssClock(
-       JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
-    JavaObject object(env, "android/location/GnssClock");
+template<class T>
+void GnssMeasurementCallback::translateGnssClock(JavaObject& object, const T& data) {
+    translateGnssClock(object, data.clock);
+}
 
-    uint32_t flags = static_cast<uint32_t>(clock->gnssClockFlags);
+template<>
+void GnssMeasurementCallback::translateGnssClock(
+       JavaObject& object, const IGnssMeasurementCallback_V1_0::GnssClock& clock) {
+    uint32_t flags = static_cast<uint32_t>(clock.gnssClockFlags);
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_LEAP_SECOND)) {
-        SET(LeapSecond, static_cast<int32_t>(clock->leapSecond));
+        SET(LeapSecond, static_cast<int32_t>(clock.leapSecond));
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_TIME_UNCERTAINTY)) {
-        SET(TimeUncertaintyNanos, clock->timeUncertaintyNs);
+        SET(TimeUncertaintyNanos, clock.timeUncertaintyNs);
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_FULL_BIAS)) {
-        SET(FullBiasNanos, clock->fullBiasNs);
+        SET(FullBiasNanos, clock.fullBiasNs);
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS)) {
-        SET(BiasNanos, clock->biasNs);
+        SET(BiasNanos, clock.biasNs);
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_BIAS_UNCERTAINTY)) {
-        SET(BiasUncertaintyNanos, clock->biasUncertaintyNs);
+        SET(BiasUncertaintyNanos, clock.biasUncertaintyNs);
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_DRIFT)) {
-        SET(DriftNanosPerSecond, clock->driftNsps);
+        SET(DriftNanosPerSecond, clock.driftNsps);
     }
 
     if (flags & static_cast<uint32_t>(GnssClockFlags::HAS_DRIFT_UNCERTAINTY)) {
-        SET(DriftUncertaintyNanosPerSecond, clock->driftUncertaintyNsps);
+        SET(DriftUncertaintyNanosPerSecond, clock.driftUncertaintyNsps);
     }
 
-    SET(TimeNanos, clock->timeNs);
-    SET(HardwareClockDiscontinuityCount, clock->hwClockDiscontinuityCount);
+    SET(TimeNanos, clock.timeNs);
+    SET(HardwareClockDiscontinuityCount, clock.hwClockDiscontinuityCount);
+}
 
-    return object.get();
+template<>
+void GnssMeasurementCallback::translateGnssClock(
+       JavaObject& object, const IGnssMeasurementCallback_V2_0::GnssData& data) {
+    auto elapsedRealtime = data.elapsedRealtime;
+    uint16_t flags = static_cast<uint16_t>(elapsedRealtime.flags);
+    if (flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) {
+        SET(ElapsedRealtimeNanos, static_cast<uint64_t>(elapsedRealtime.timestampNs));
+    }
+    if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
+        SET(ElapsedRealtimeUncertaintyNanos, static_cast<uint64_t>(elapsedRealtime.timeUncertaintyNs));
+    }
+    translateGnssClock(object, data.clock);
 }
 
 template<class T>
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 5ffed03..2cfaebf 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -54,6 +54,7 @@
 int register_android_hardware_display_DisplayViewport(JNIEnv* env);
 int register_android_server_net_NetworkStatsService(JNIEnv* env);
 int register_android_server_security_VerityUtils(JNIEnv* env);
+int register_android_server_am_AppCompactor(JNIEnv* env);
 };
 
 using namespace android;
@@ -101,5 +102,6 @@
     register_android_hardware_display_DisplayViewport(env);
     register_android_server_net_NetworkStatsService(env);
     register_android_server_security_VerityUtils(env);
+    register_android_server_am_AppCompactor(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f6de82d..633367a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -58,7 +58,14 @@
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF;
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -3475,15 +3482,15 @@
 
     static void validateQualityConstant(int quality) {
         switch (quality) {
-            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-            case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
-            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
-            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
+            case PASSWORD_QUALITY_UNSPECIFIED:
+            case PASSWORD_QUALITY_BIOMETRIC_WEAK:
+            case PASSWORD_QUALITY_SOMETHING:
+            case PASSWORD_QUALITY_NUMERIC:
+            case PASSWORD_QUALITY_NUMERIC_COMPLEX:
+            case PASSWORD_QUALITY_ALPHABETIC:
+            case PASSWORD_QUALITY_ALPHANUMERIC:
+            case PASSWORD_QUALITY_COMPLEX:
+            case PASSWORD_QUALITY_MANAGED:
                 return;
         }
         throw new IllegalArgumentException("Invalid quality constant: 0x"
@@ -4747,41 +4754,36 @@
             // setActivePasswordState has never been called for it.
             metrics = new PasswordMetrics();
         }
+
         return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, parent);
     }
 
     /**
-     * Returns {@code true} if the password represented by the {@code passwordMetrics} argument
+     * Returns {@code true} if the password represented by the {@code metrics} argument
      * sufficiently fulfills the password requirements for the user corresponding to
-     * {@code userHandle} (or its parent, if {@code parent} is set to {@code true}).
+     * {@code userId} (or its parent, if {@code parent} is set to {@code true}).
      */
     private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
-            PasswordMetrics passwordMetrics, int userHandle, boolean parent) {
-        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
+            PasswordMetrics metrics, @UserIdInt int userId, boolean parent) {
+        final int requiredQuality = getPasswordQuality(null, userId, parent);
 
-        if (passwordMetrics.quality < requiredPasswordQuality) {
+        if (requiredQuality >= PASSWORD_QUALITY_NUMERIC
+                && metrics.length < getPasswordMinimumLength(null, userId, parent)) {
             return false;
         }
-        if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
-                && passwordMetrics.length < getPasswordMinimumLength(
-                        null, userHandle, parent)) {
-            return false;
+
+        // PASSWORD_QUALITY_COMPLEX doesn't represent actual password quality, it means that number
+        // of characters of each class should be checked instead of quality itself.
+        if (requiredQuality == PASSWORD_QUALITY_COMPLEX) {
+            return metrics.upperCase >= getPasswordMinimumUpperCase(null, userId, parent)
+                    && metrics.lowerCase >= getPasswordMinimumLowerCase(null, userId, parent)
+                    && metrics.letters >= getPasswordMinimumLetters(null, userId, parent)
+                    && metrics.numeric >= getPasswordMinimumNumeric(null, userId, parent)
+                    && metrics.symbols >= getPasswordMinimumSymbols(null, userId, parent)
+                    && metrics.nonLetter >= getPasswordMinimumNonLetter(null, userId, parent);
+        } else {
+            return metrics.quality >= requiredQuality;
         }
-        if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
-            return true;
-        }
-        return passwordMetrics.upperCase >= getPasswordMinimumUpperCase(
-                    null, userHandle, parent)
-                && passwordMetrics.lowerCase >= getPasswordMinimumLowerCase(
-                        null, userHandle, parent)
-                && passwordMetrics.letters >= getPasswordMinimumLetters(
-                        null, userHandle, parent)
-                && passwordMetrics.numeric >= getPasswordMinimumNumeric(
-                        null, userHandle, parent)
-                && passwordMetrics.symbols >= getPasswordMinimumSymbols(
-                        null, userHandle, parent)
-                && passwordMetrics.nonLetter >= getPasswordMinimumNonLetter(
-                        null, userHandle, parent);
     }
 
     @Override
@@ -5042,14 +5044,13 @@
         int quality;
         synchronized (getLockObject()) {
             quality = getPasswordQuality(null, userHandle, /* parent */ false);
-            if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
+            if (quality == PASSWORD_QUALITY_MANAGED) {
                 quality = PASSWORD_QUALITY_UNSPECIFIED;
             }
             // TODO(b/120484642): remove getBytes() below
             final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes());
             final int realQuality = metrics.quality;
-            if (realQuality < quality
-                    && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+            if (realQuality < quality && quality != PASSWORD_QUALITY_COMPLEX) {
                 Slog.w(LOG_TAG, "resetPassword: password quality 0x"
                         + Integer.toHexString(realQuality)
                         + " does not meet required quality 0x"
@@ -5063,7 +5064,7 @@
                         + " does not meet required length " + length);
                 return false;
             }
-            if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+            if (quality == PASSWORD_QUALITY_COMPLEX) {
                 int neededLetters = getPasswordMinimumLetters(null, userHandle, /* parent */ false);
                 if(metrics.letters < neededLetters) {
                     Slog.w(LOG_TAG, "resetPassword: number of letters " + metrics.letters
@@ -5132,11 +5133,14 @@
         final boolean result;
         try {
             if (token == null) {
+                // This is the legacy reset password for DPM. Here we want to be able to override
+                // the old device password without necessarily knowing it.
                 if (!TextUtils.isEmpty(password)) {
                     mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
-                            userHandle);
+                            userHandle, /*allowUntrustedChange */true);
                 } else {
-                    mLockPatternUtils.clearLock(null, userHandle);
+                    mLockPatternUtils.clearLock(null, userHandle,
+                            /*allowUntrustedChange */ true);
                 }
                 result = true;
             } else {
@@ -5245,12 +5249,11 @@
                 // would allow bypassing of the maximum time to lock.
                 mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
+            getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+                    UserHandle.USER_SYSTEM, timeMs);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
-
-        getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
-                UserHandle.USER_SYSTEM, timeMs);
     }
 
     private void updateProfileLockTimeoutLocked(@UserIdInt int userId) {
@@ -5268,8 +5271,13 @@
         }
         policy.mLastMaximumTimeToLock = timeMs;
 
-        getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
-                userId, policy.mLastMaximumTimeToLock);
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+                    userId, policy.mLastMaximumTimeToLock);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 419f52c..d4ccb0b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -849,7 +849,7 @@
     private void startOtherServices() {
         final Context context = mSystemContext;
         VibratorService vibrator = null;
-        DynamicAndroidService dynamicAndroid = null;
+        DynamicSystemService dynamicSystem = null;
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
         IpSecService ipSecService = null;
@@ -968,9 +968,9 @@
             ServiceManager.addService("vibrator", vibrator);
             traceEnd();
 
-            traceBeginAndSlog("StartDynamicAndroidService");
-            dynamicAndroid = new DynamicAndroidService(context);
-            ServiceManager.addService("dynamic_android", dynamicAndroid);
+            traceBeginAndSlog("StartDynamicSystemService");
+            dynamicSystem = new DynamicSystemService(context);
+            ServiceManager.addService("dynamic_system", dynamicSystem);
             traceEnd();
 
             if (!isWatch) {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 486d15d..9e1d44b 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,3 +1,61 @@
+// AIDL interfaces between the core system and the networking mainline module.
+aidl_interface {
+    name: "ipmemorystore-aidl-interfaces",
+    local_include_dir: "java",
+    srcs: [
+        // TODO: Define and use a filegroup for these files, since they're also used in
+        // networkstack-aidl-interfaces. This does not appear to work at the moment.
+        "java/android/net/IIpMemoryStore.aidl",
+        "java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "java/android/net/ipmemorystore/**/*.aidl",
+    ],
+    backend: {
+        ndk: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+    api_dir: "aidl/networkstack",
+}
+
+aidl_interface {
+    name: "networkstack-aidl-interfaces",
+    local_include_dir: "java",
+    include_dirs: ["frameworks/base/core/java"],  // For framework parcelables.
+    srcs: [
+        "java/android/net/ApfCapabilitiesParcelable.aidl",
+        "java/android/net/DhcpResultsParcelable.aidl",
+        "java/android/net/IIpMemoryStore.aidl",
+        "java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "java/android/net/INetworkMonitor.aidl",
+        "java/android/net/INetworkMonitorCallbacks.aidl",
+        "java/android/net/INetworkStackConnector.aidl",
+        "java/android/net/INetworkStackStatusCallback.aidl",
+        "java/android/net/InitialConfigurationParcelable.aidl",
+        "java/android/net/PrivateDnsConfigParcel.aidl",
+        "java/android/net/ProvisioningConfigurationParcelable.aidl",
+        "java/android/net/StaticIpConfigurationParcelable.aidl",
+        "java/android/net/TcpKeepalivePacketDataParcelable.aidl",
+        "java/android/net/dhcp/DhcpServingParamsParcel.aidl",
+        "java/android/net/dhcp/IDhcpServer.aidl",
+        "java/android/net/dhcp/IDhcpServerCallbacks.aidl",
+        "java/android/net/ip/IIpClient.aidl",
+        "java/android/net/ip/IIpClientCallbacks.aidl",
+        "java/android/net/ipmemorystore/**/*.aidl",
+    ],
+    backend: {
+        ndk: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+    api_dir: "aidl/networkstack",
+}
+
 java_library_static {
     name: "services.net",
     srcs: ["java/**/*.java"],
diff --git a/core/java/android/net/ApfCapabilitiesParcelable.aidl b/services/net/java/android/net/ApfCapabilitiesParcelable.aidl
similarity index 100%
rename from core/java/android/net/ApfCapabilitiesParcelable.aidl
rename to services/net/java/android/net/ApfCapabilitiesParcelable.aidl
diff --git a/core/java/android/net/DhcpResultsParcelable.aidl b/services/net/java/android/net/DhcpResultsParcelable.aidl
similarity index 100%
rename from core/java/android/net/DhcpResultsParcelable.aidl
rename to services/net/java/android/net/DhcpResultsParcelable.aidl
diff --git a/core/java/android/net/IIpMemoryStore.aidl b/services/net/java/android/net/IIpMemoryStore.aidl
similarity index 100%
rename from core/java/android/net/IIpMemoryStore.aidl
rename to services/net/java/android/net/IIpMemoryStore.aidl
diff --git a/core/java/android/net/IIpMemoryStoreCallbacks.aidl b/services/net/java/android/net/IIpMemoryStoreCallbacks.aidl
similarity index 100%
rename from core/java/android/net/IIpMemoryStoreCallbacks.aidl
rename to services/net/java/android/net/IIpMemoryStoreCallbacks.aidl
diff --git a/core/java/android/net/INetworkMonitor.aidl b/services/net/java/android/net/INetworkMonitor.aidl
similarity index 100%
rename from core/java/android/net/INetworkMonitor.aidl
rename to services/net/java/android/net/INetworkMonitor.aidl
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/services/net/java/android/net/INetworkMonitorCallbacks.aidl
similarity index 100%
rename from core/java/android/net/INetworkMonitorCallbacks.aidl
rename to services/net/java/android/net/INetworkMonitorCallbacks.aidl
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/services/net/java/android/net/INetworkStackConnector.aidl
similarity index 100%
rename from core/java/android/net/INetworkStackConnector.aidl
rename to services/net/java/android/net/INetworkStackConnector.aidl
diff --git a/core/java/android/net/INetworkStackStatusCallback.aidl b/services/net/java/android/net/INetworkStackStatusCallback.aidl
similarity index 100%
rename from core/java/android/net/INetworkStackStatusCallback.aidl
rename to services/net/java/android/net/INetworkStackStatusCallback.aidl
diff --git a/core/java/android/net/InitialConfigurationParcelable.aidl b/services/net/java/android/net/InitialConfigurationParcelable.aidl
similarity index 100%
rename from core/java/android/net/InitialConfigurationParcelable.aidl
rename to services/net/java/android/net/InitialConfigurationParcelable.aidl
diff --git a/core/java/android/net/PrivateDnsConfigParcel.aidl b/services/net/java/android/net/PrivateDnsConfigParcel.aidl
similarity index 100%
rename from core/java/android/net/PrivateDnsConfigParcel.aidl
rename to services/net/java/android/net/PrivateDnsConfigParcel.aidl
diff --git a/core/java/android/net/ProvisioningConfigurationParcelable.aidl b/services/net/java/android/net/ProvisioningConfigurationParcelable.aidl
similarity index 100%
rename from core/java/android/net/ProvisioningConfigurationParcelable.aidl
rename to services/net/java/android/net/ProvisioningConfigurationParcelable.aidl
diff --git a/core/java/android/net/StaticIpConfigurationParcelable.aidl b/services/net/java/android/net/StaticIpConfigurationParcelable.aidl
similarity index 100%
rename from core/java/android/net/StaticIpConfigurationParcelable.aidl
rename to services/net/java/android/net/StaticIpConfigurationParcelable.aidl
diff --git a/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl b/services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl
similarity index 100%
rename from core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
rename to services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl
diff --git a/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl b/services/net/java/android/net/dhcp/DhcpServingParamsParcel.aidl
similarity index 100%
rename from core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
rename to services/net/java/android/net/dhcp/DhcpServingParamsParcel.aidl
diff --git a/core/java/android/net/dhcp/IDhcpServer.aidl b/services/net/java/android/net/dhcp/IDhcpServer.aidl
similarity index 100%
rename from core/java/android/net/dhcp/IDhcpServer.aidl
rename to services/net/java/android/net/dhcp/IDhcpServer.aidl
diff --git a/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl b/services/net/java/android/net/dhcp/IDhcpServerCallbacks.aidl
similarity index 100%
rename from core/java/android/net/dhcp/IDhcpServerCallbacks.aidl
rename to services/net/java/android/net/dhcp/IDhcpServerCallbacks.aidl
diff --git a/core/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl
similarity index 100%
rename from core/java/android/net/ip/IIpClient.aidl
rename to services/net/java/android/net/ip/IIpClient.aidl
diff --git a/core/java/android/net/ip/IIpClientCallbacks.aidl b/services/net/java/android/net/ip/IIpClientCallbacks.aidl
similarity index 100%
rename from core/java/android/net/ip/IIpClientCallbacks.aidl
rename to services/net/java/android/net/ip/IIpClientCallbacks.aidl
diff --git a/core/java/android/net/ipmemorystore/Blob.aidl b/services/net/java/android/net/ipmemorystore/Blob.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/Blob.aidl
rename to services/net/java/android/net/ipmemorystore/Blob.aidl
diff --git a/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/services/net/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
rename to services/net/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
diff --git a/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/services/net/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
rename to services/net/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
diff --git a/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
rename to services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
diff --git a/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
rename to services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
diff --git a/core/java/android/net/ipmemorystore/IOnStatusListener.aidl b/services/net/java/android/net/ipmemorystore/IOnStatusListener.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/IOnStatusListener.aidl
rename to services/net/java/android/net/ipmemorystore/IOnStatusListener.aidl
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
rename to services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
rename to services/net/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
diff --git a/core/java/android/net/ipmemorystore/StatusParcelable.aidl b/services/net/java/android/net/ipmemorystore/StatusParcelable.aidl
similarity index 100%
rename from core/java/android/net/ipmemorystore/StatusParcelable.aidl
rename to services/net/java/android/net/ipmemorystore/StatusParcelable.aidl
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 2e5efbd..212d2a8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -112,7 +112,7 @@
                             Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0,
                     mPersistedState.global.getOrDefault(
                             Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90),
-                    mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVER_MODE, 0),
+                    mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVE_MODE, 0),
                     mPersistedState.global.getOrDefault(
                             Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0,
                     mPersistedState.global.getOrDefault(
@@ -321,7 +321,7 @@
     @Test
     public void testAutoBatterySaver() {
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVE_MODE, 0);
 
         assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(100, mPersistedState.batteryLevel);
@@ -789,7 +789,7 @@
                 .thenReturn(true);
         initDevice();
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVE_MODE, 0);
 
         mTarget.setBatterySaverEnabledManually(true);
 
@@ -906,8 +906,8 @@
     @Test
     public void testAutoBatterySaver_smartBatterySaverEnabled() {
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
-                PowerManager.POWER_SAVER_MODE_DYNAMIC);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
 
         assertEquals(false, mDevice.batterySaverEnabled);
@@ -1029,8 +1029,8 @@
         // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's
         // not enabled.
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
-                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
 
         assertEquals(false, mDevice.batterySaverEnabled);
@@ -1138,8 +1138,8 @@
         // not enabled.
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
-                PowerManager.POWER_SAVER_MODE_DYNAMIC);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
 
         assertEquals(false, mDevice.batterySaverEnabled);
diff --git a/services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
similarity index 68%
rename from services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java
rename to services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index 1494284..4a9dd97 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -16,28 +16,28 @@
 
 package com.android.server;
 
-import android.os.IDynamicAndroidService;
 import android.os.ServiceManager;
+import android.os.image.IDynamicSystemService;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
-public class DynamicAndroidServiceTest extends AndroidTestCase {
-    private static final String TAG = "DynamicAndroidServiceTests";
-    private IDynamicAndroidService mService;
+public class DynamicSystemServiceTest extends AndroidTestCase {
+    private static final String TAG = "DynamicSystemServiceTests";
+    private IDynamicSystemService mService;
 
     @Override
     protected void setUp() throws Exception {
         mService =
-                IDynamicAndroidService.Stub.asInterface(
-                        ServiceManager.getService("dynamic_android"));
+                IDynamicSystemService.Stub.asInterface(
+                        ServiceManager.getService("dynamic_system"));
     }
 
     @LargeTest
     public void test1() {
-        assertTrue("dynamic_android service available", mService != null);
+        assertTrue("dynamic_system service available", mService != null);
         try {
             mService.startInstallation(1 << 20, 8 << 30);
-            fail("DynamicAndroidService did not throw SecurityException as expected");
+            fail("DynamicSystemService did not throw SecurityException as expected");
         } catch (SecurityException e) {
             // expected
         } catch (Exception e) {
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index caf6c9c..4b3d9cf 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1068,6 +1068,12 @@
     }
 
     @Override
+    public ParceledListSlice getDeclaredSharedLibraries(String packageName, int flags, int userId)
+            throws RemoteException {
+        return null;
+    }
+
+    @Override
     public boolean canRequestPackageInstalls(String packageName, int userId)
         throws RemoteException {
         return false;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
index 94d21dd..ca4330f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
@@ -61,12 +61,12 @@
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         // clear password
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
-                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, true);
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
 
         // set a new password
         mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -81,7 +81,7 @@
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         // Untrusted change password
         mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
         assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
 
@@ -99,7 +99,7 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         // Untrusted change password
         mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
 
         // Verify the password
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
@@ -124,10 +124,12 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         // Untrusted change password
-        assertExpectException(IllegalStateException.class, /* messageRegex= */ null,
+        assertExpectException(
+                IllegalStateException.class,
+                /* messageRegex= */ "Untrusted credential reset not possible without cached SP",
                 () -> mService.setLockCredential(newPassword,
                         LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                        PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
+                        PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true));
         assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
 
         // Verify the new password doesn't work but the old one still does
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 6e0ba3c..255e694b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -85,9 +85,9 @@
 
         try {
             mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
-                    "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                    "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
             fail("Did not fail when enrolling using incorrect credential");
-        } catch (RemoteException expected) {
+        } catch (IllegalStateException expected) {
             assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
         }
         assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
@@ -97,7 +97,7 @@
         final String PASSWORD = "password";
         initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
         mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
-                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
         assertFalse(mService.havePassword(PRIMARY_USER_ID));
         assertFalse(mService.havePattern(PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
@@ -108,7 +108,7 @@
         final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
         mService.setLockCredential(firstUnifiedPassword.getBytes(),
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
+                null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
@@ -143,15 +143,16 @@
         mStorageManager.setIgnoreBadUnlock(true);
         // Change primary password and verify that profile SID remains
         mService.setLockCredential(secondUnifiedPassword.getBytes(),
-                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, firstUnifiedPassword.getBytes(),
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         mStorageManager.setIgnoreBadUnlock(false);
         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
         assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
 
         // Clear unified challenge
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
-                secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID,
+                false);
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
@@ -162,7 +163,7 @@
         final String profilePassword = "testManagedProfileSeparateChallenge-profile";
         mService.setLockCredential(primaryPassword.getBytes(),
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
         /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
          * credential as part of verifyCredential() before the new credential is committed in
          * StorageManager. So we relax the check in our mock StorageManager to allow that.
@@ -170,7 +171,7 @@
         mStorageManager.setIgnoreBadUnlock(true);
         mService.setLockCredential(profilePassword.getBytes(),
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID);
+                PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID, false);
         mStorageManager.setIgnoreBadUnlock(false);
 
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
@@ -197,7 +198,7 @@
         // Change primary credential and make sure we don't affect profile
         mStorageManager.setIgnoreBadUnlock(true);
         mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         mStorageManager.setIgnoreBadUnlock(false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
@@ -208,7 +209,7 @@
     private void testCreateCredential(int userId, String credential, int type, int quality)
             throws RemoteException {
         mService.setLockCredential(credential.getBytes(), type, null, quality,
-                userId);
+                userId, false);
         assertVerifyCredentials(userId, credential, type, -1);
     }
 
@@ -218,7 +219,7 @@
 
         try {
             mService.setLockCredential(credential.getBytes(), type, null, quality,
-                    userId);
+                    userId, false);
             fail("An exception should have been thrown.");
         } catch (UnsupportedOperationException e) {
             // Success - the exception was expected.
@@ -233,7 +234,7 @@
         final long sid = 1234;
         initializeStorageWithCredential(userId, oldCredential, oldType, sid);
         mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
-                quality, userId);
+                quality, userId, false);
         assertVerifyCredentials(userId, newCredential, newType, sid);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 6a07a45..58055e5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -102,7 +102,7 @@
 
         disableSyntheticPassword();
         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
         enableSyntheticPassword();
@@ -127,7 +127,7 @@
                 : PASSWORD_QUALITY_UNSPECIFIED;
         int type = password != null ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
                 : LockPatternUtils.CREDENTIAL_TYPE_NONE;
-        mService.setLockCredential(password, type, null, quality, userId);
+        mService.setLockCredential(password, type, null, quality, userId, false);
     }
 
     public void testSyntheticPasswordChangeCredential() throws RemoteException {
@@ -137,7 +137,7 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -166,12 +166,12 @@
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         // clear password
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
-                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
         assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
 
         // set a new password
         mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -186,7 +186,7 @@
 
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -245,7 +245,7 @@
         final byte[] password = "getASyntheticPassword".getBytes();
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
-                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
 
         reset(mAuthSecretService);
         mService.onUnlockUser(PRIMARY_USER_ID);
@@ -257,7 +257,7 @@
         final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
         disableSyntheticPassword();
         mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
@@ -294,9 +294,9 @@
                 "testManagedProfileSeparateChallengeMigration-profile".getBytes();
         disableSyntheticPassword();
         mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
@@ -404,7 +404,7 @@
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
-                PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
 
         mLocalService.setLockCredentialWithToken(newPassword,
                 LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
@@ -443,7 +443,7 @@
         // Set up pre-SP user password
         disableSyntheticPassword();
         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         enableSyntheticPassword();
 
         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
@@ -491,12 +491,12 @@
     public void testgetHashFactorPrimaryUser() throws RemoteException {
         final byte[] password = "password".getBytes();
         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
         assertNotNull(hashFactor);
 
         mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
-                password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+                password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
         final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
         assertNotNull(newHashFactor);
         // Hash factor should never change after password change/removal
@@ -506,7 +506,7 @@
     public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
         final byte[] pattern = "1236".getBytes();
         mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+                null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
     }
@@ -515,9 +515,9 @@
         final byte[] primaryPassword = "primary".getBytes();
         final byte[] profilePassword = "profile".getBytes();
         mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
         mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
+                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
         assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a8da80e..426122a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -353,7 +353,6 @@
         FileOutputStream fos = mPolicyFile.startWrite();
         fos.write(preupgradeXml.getBytes());
         mPolicyFile.finishWrite(fos);
-        FileInputStream fStream = new FileInputStream(mFile);
 
         // Setup managed services
         mListener = mListeners.new ManagedServiceInfo(
@@ -369,6 +368,8 @@
         dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
         when(mConditionProviders.getConfig()).thenReturn(dndConfig);
 
+        when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
+
         try {
             mService.init(mTestableLooper.getLooper(),
                     mPackageManager, mPackageManagerClient, mockLightsManager,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 23bae88..de4fb98 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -37,6 +37,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseIntArray;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
@@ -118,6 +119,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnIntentStarted() throws Exception {
         Intent intent = new Intent("action 1");
 
@@ -128,6 +130,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnIntentFailed() throws Exception {
         testOnIntentStarted();
 
@@ -143,6 +146,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunched() throws Exception {
         testOnIntentStarted();
 
@@ -154,6 +158,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunchFinished() throws Exception {
        testOnActivityLaunched();
 
@@ -168,6 +173,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunchCancelled() throws Exception {
        testOnActivityLaunched();
 
@@ -181,6 +187,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunchedTrampoline() throws Exception {
         testOnIntentStarted();
 
@@ -197,6 +204,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunchFinishedTrampoline() throws Exception {
        testOnActivityLaunchedTrampoline();
 
@@ -211,6 +219,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 129138370)
     public void testOnActivityLaunchCancelledTrampoline() throws Exception {
        testOnActivityLaunchedTrampoline();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 4279c41..03969da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -50,6 +50,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
@@ -476,6 +477,28 @@
         }
     }
 
+    @Test
+    public void forceShowSystemBars_clearsSystemUIFlags() {
+        synchronized (mWm.mGlobalLock) {
+            mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
+            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+            mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
+            mDisplayPolicy.setForceShowSystemBars(true);
+            addWindow(mWindow);
+
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            // triggers updateSystemUiVisibilityLw which will reset the flags as needed
+            int finishPostLayoutPolicyLw = mDisplayPolicy.focusChangedLw(mWindow, mWindow);
+
+            assertEquals(WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT, finishPostLayoutPolicyLw);
+            assertEquals(0, mDisplayPolicy.mLastSystemUiFlags);
+            assertEquals(0, mWindow.mAttrs.systemUiVisibility);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        }
+    }
+
     /**
      * Asserts that {@code actual} is inset by the given amounts from the full display rect.
      *
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 68e7470..08e6ce4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -29,7 +30,9 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -512,6 +515,52 @@
     }
 
     @Test
+    public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
+        // Create some set of tasks, some of which are visible and some are not
+        TaskRecord homeTask = setTaskActivityType(
+                createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
+                ACTIVITY_TYPE_HOME);
+        homeTask.mUserSetupComplete = true;
+        mRecentTasks.add(homeTask);
+        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+                .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                .build();
+        excludedTask1.mUserSetupComplete = true;
+        mRecentTasks.add(excludedTask1);
+
+        // Expect that the first visible excluded-from-recents task is visible
+        assertGetRecentTasksOrder(0 /* flags */, excludedTask1);
+    }
+
+    @Test
+    public void testVisibleTasks_excludedFromRecents_withExcluded() {
+        // Create some set of tasks, some of which are visible and some are not
+        TaskRecord t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
+        t1.mUserSetupComplete = true;
+        mRecentTasks.add(t1);
+        TaskRecord homeTask = setTaskActivityType(
+                createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
+                ACTIVITY_TYPE_HOME);
+        homeTask.mUserSetupComplete = true;
+        mRecentTasks.add(homeTask);
+        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+                .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                .build();
+        excludedTask1.mUserSetupComplete = true;
+        mRecentTasks.add(excludedTask1);
+        TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+                .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                .build();
+        excludedTask2.mUserSetupComplete = true;
+        mRecentTasks.add(excludedTask2);
+        TaskRecord t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
+        t2.mUserSetupComplete = true;
+        mRecentTasks.add(t2);
+
+        assertGetRecentTasksOrder(RECENT_WITH_EXCLUDED, t2, excludedTask2, excludedTask1, t1);
+    }
+
+    @Test
     public void testVisibleTasks_minNum() {
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
@@ -830,7 +879,7 @@
     }
 
     /**
-     * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
+     * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
      * should be ordered from least to most recent.
      */
     private void assertRecentTasksOrder(TaskRecord... expectedTasks) {
@@ -841,6 +890,22 @@
         }
     }
 
+    /**
+     * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
+     * should be ordered from least to most recent.
+     */
+    private void assertGetRecentTasksOrder(int getRecentTaskFlags, TaskRecord... expectedTasks) {
+        doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
+        doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
+        List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
+                true /* getTasksAllowed */, false /* getDetailedTasks */,
+                TEST_USER_0_ID, 0).getList();
+        assertTrue(expectedTasks.length == infos.size());
+        for (int i = 0; i < infos.size(); i++)  {
+            assertTrue(expectedTasks[i].taskId == infos.get(i).taskId);
+        }
+    }
+
     private void assertNotRestoreTask(Runnable action) {
         // Verify stack count doesn't change because task with fullscreen mode and standard type
         // would have its own stack.
@@ -1018,7 +1083,7 @@
 
         @Override
         protected RecentTasks createRecentTasks() {
-            return new TestRecentTasks(this, mTaskPersister);
+            return spy(new TestRecentTasks(this, mTaskPersister));
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index c5df85c..83aa620 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -38,7 +38,7 @@
     @Override
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
             Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
-            Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+            Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
     }
 
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 81553a3..afa35b4 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -51,6 +52,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int TRANSPORT_TYPE_WWAN = 1;
 
     /**
@@ -58,6 +60,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int TRANSPORT_TYPE_WLAN = 2;
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5f9ef3c..0a9b904 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1543,6 +1543,21 @@
             "allow_non_emergency_calls_in_ecm_bool";
 
     /**
+     * Time that the telephony framework stays in "emergency SMS mode" after an emergency SMS is
+     * sent to the network. This is used by carriers to configure the time
+     * {@link TelephonyManager#isInEmergencySmsMode()} will be true after an emergency SMS is sent.
+     * This is used by GNSS to override user location permissions so that the carrier network can
+     * get the user's location for emergency services.
+     *
+     * The default is 0, which means that this feature is disabled. The maximum value for this timer
+     * is 300000 mS (5 minutes).
+     *
+     * @hide
+     */
+    public static final String KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT =
+            "emergency_sms_mode_timer_ms_int";
+
+    /**
      * Flag indicating whether to allow carrier video calls to emergency numbers.
      * When {@code true}, video calls to emergency numbers will be allowed.  When {@code false},
      * video calls to emergency numbers will be initiated as audio-only calls instead.
@@ -1847,12 +1862,32 @@
             "use_wfc_home_network_mode_in_roaming_network_bool";
 
     /**
+     * Flag specifying whether the carrier is allowed to use metered network to download a
+     * certificate of Carrier-WiFi.
+     * {@code false} - default value.
+     *
+     * @hide
+     */
+    public static final String KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL =
+            "allow_metered_network_for_cert_download_bool";
+
+    /**
      * Carrier specified WiFi networks.
      * @hide
      */
     public static final String KEY_CARRIER_WIFI_STRING_ARRAY = "carrier_wifi_string_array";
 
     /**
+     * Base64 Encoding method the carrier will use for encoding encrypted IMSI and SSID.
+     * The value set as below:
+     * 2045 - RFC2045 (default value)
+     * 4648 - RFC4648
+     *
+     * @hide
+     */
+    public static final String KEY_IMSI_ENCODING_METHOD_INT = "imsi_encoding_method_int";
+
+    /**
      * Time delay (in ms) after which we show the notification to switch the preferred
      * network.
      * @hide
@@ -2667,6 +2702,14 @@
             "cdma_enhanced_roaming_indicator_for_home_network_int_array";
 
     /**
+     * Determines whether wifi calling location privacy policy is shown.
+     *
+     * @hide
+     */
+    public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL =
+            "show_wfc_location_privacy_policy_bool";
+
+    /**
      * Indicates use 3GPP application to replace 3GPP2 application even if it's a CDMA/CDMA-LTE
      * phone, becasue some carriers's CSIM application is present but not supported.
      * @hide
@@ -2917,6 +2960,7 @@
         sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
+        sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
         sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
         sDefaults.putInt(
@@ -2982,7 +3026,9 @@
         sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
         sDefaults.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
         sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL, false);
         sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
+        sDefaults.putInt(KEY_IMSI_ENCODING_METHOD_INT, 2045);
         sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
         sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
         sDefaults.putBoolean(KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL, true);
@@ -3073,6 +3119,7 @@
                 });
         sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
         sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
                 false);
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
similarity index 65%
rename from telephony/java/android/telephony/DataSpecificRegistrationStates.java
rename to telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 8eb345a..fbf488e 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -1,7 +1,24 @@
+/*
+ * Copyright 2018 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.telephony;
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -13,7 +30,8 @@
  * @hide
  */
 @SystemApi
-public final class DataSpecificRegistrationStates implements Parcelable{
+@TestApi
+public final class DataSpecificRegistrationInfo implements Parcelable {
     /**
      * @hide
      * The maximum number of simultaneous Data Calls that
@@ -53,27 +71,27 @@
     /**
      * Provides network support info for LTE VoPS and LTE Emergency bearer support
      */
-    private final LteVopsSupportInfo lteVopsSupportInfo;
+    private final LteVopsSupportInfo mLteVopsSupportInfo;
 
     /**
      * @hide
      */
-    DataSpecificRegistrationStates(
+    DataSpecificRegistrationInfo(
             int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
             boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
         this.maxDataCalls = maxDataCalls;
         this.isDcNrRestricted = isDcNrRestricted;
         this.isNrAvailable = isNrAvailable;
         this.isEnDcAvailable = isEnDcAvailable;
-        this.lteVopsSupportInfo = lteVops;
+        this.mLteVopsSupportInfo = lteVops;
     }
 
-    private DataSpecificRegistrationStates(Parcel source) {
+    private DataSpecificRegistrationInfo(Parcel source) {
         maxDataCalls = source.readInt();
         isDcNrRestricted = source.readBoolean();
         isNrAvailable = source.readBoolean();
         isEnDcAvailable = source.readBoolean();
-        lteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
+        mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
     }
 
     @Override
@@ -82,7 +100,7 @@
         dest.writeBoolean(isDcNrRestricted);
         dest.writeBoolean(isNrAvailable);
         dest.writeBoolean(isEnDcAvailable);
-        lteVopsSupportInfo.writeToParcel(dest, flags);
+        mLteVopsSupportInfo.writeToParcel(dest, flags);
     }
 
     @Override
@@ -98,7 +116,7 @@
                 .append(" isDcNrRestricted = " + isDcNrRestricted)
                 .append(" isNrAvailable = " + isNrAvailable)
                 .append(" isEnDcAvailable = " + isEnDcAvailable)
-                .append(lteVopsSupportInfo.toString())
+                .append(mLteVopsSupportInfo.toString())
                 .append(" }")
                 .toString();
     }
@@ -106,41 +124,41 @@
     @Override
     public int hashCode() {
         return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
-            lteVopsSupportInfo);
+                mLteVopsSupportInfo);
     }
 
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
 
-        if (!(o instanceof DataSpecificRegistrationStates)) return false;
+        if (!(o instanceof DataSpecificRegistrationInfo)) return false;
 
-        DataSpecificRegistrationStates other = (DataSpecificRegistrationStates) o;
+        DataSpecificRegistrationInfo other = (DataSpecificRegistrationInfo) o;
         return this.maxDataCalls == other.maxDataCalls
                 && this.isDcNrRestricted == other.isDcNrRestricted
                 && this.isNrAvailable == other.isNrAvailable
                 && this.isEnDcAvailable == other.isEnDcAvailable
-                && this.lteVopsSupportInfo.equals(other.lteVopsSupportInfo);
+                && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<DataSpecificRegistrationStates> CREATOR =
-            new Parcelable.Creator<DataSpecificRegistrationStates>() {
+    public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR =
+            new Parcelable.Creator<DataSpecificRegistrationInfo>() {
                 @Override
-                public DataSpecificRegistrationStates createFromParcel(Parcel source) {
-                    return new DataSpecificRegistrationStates(source);
+                public DataSpecificRegistrationInfo createFromParcel(Parcel source) {
+                    return new DataSpecificRegistrationInfo(source);
                 }
 
                 @Override
-                public DataSpecificRegistrationStates[] newArray(int size) {
-                    return new DataSpecificRegistrationStates[size];
+                public DataSpecificRegistrationInfo[] newArray(int size) {
+                    return new DataSpecificRegistrationInfo[size];
                 }
             };
 
     /**
-     * @return LteVopsSupportInfo
+     * @return The LTE VOPS (Voice over Packet Switched) support information
      */
     @NonNull
     public LteVopsSupportInfo getLteVopsSupportInfo() {
-        return lteVopsSupportInfo;
+        return mLteVopsSupportInfo;
     }
 }
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
index ee45f07..ec9f078 100644
--- a/telephony/java/android/telephony/LteVopsSupportInfo.java
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -30,6 +31,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class LteVopsSupportInfo implements Parcelable {
 
     /**@hide*/
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 9145b25..1dc2997 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.TransportType;
@@ -38,6 +39,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class NetworkRegistrationInfo implements Parcelable {
     /**
      * Network domain
@@ -174,10 +176,10 @@
     private CellIdentity mCellIdentity;
 
     @Nullable
-    private VoiceSpecificRegistrationStates mVoiceSpecificStates;
+    private VoiceSpecificRegistrationInfo mVoiceSpecificInfo;
 
     @Nullable
-    private DataSpecificRegistrationStates mDataSpecificStates;
+    private DataSpecificRegistrationInfo mDataSpecificInfo;
 
     /**
      * @param domain Network domain. Must be a {@link Domain}. For transport type
@@ -234,7 +236,7 @@
         this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
                 emergencyOnly, availableServices, cellIdentity);
 
-        mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator,
+        mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
                 systemIsInPrl, defaultRoamingIndicator);
     }
 
@@ -253,9 +255,9 @@
         this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
                 emergencyOnly, availableServices, cellIdentity);
 
-        mDataSpecificStates = new DataSpecificRegistrationStates(
+        mDataSpecificInfo = new DataSpecificRegistrationInfo(
                 maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
-        updateNrState(mDataSpecificStates);
+        updateNrState(mDataSpecificInfo);
     }
 
     private NetworkRegistrationInfo(Parcel source) {
@@ -269,10 +271,10 @@
         mAvailableServices = new ArrayList<>();
         source.readList(mAvailableServices, Integer.class.getClassLoader());
         mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
-        mVoiceSpecificStates = source.readParcelable(
-                VoiceSpecificRegistrationStates.class.getClassLoader());
-        mDataSpecificStates = source.readParcelable(
-                DataSpecificRegistrationStates.class.getClassLoader());
+        mVoiceSpecificInfo = source.readParcelable(
+                VoiceSpecificRegistrationInfo.class.getClassLoader());
+        mDataSpecificInfo = source.readParcelable(
+                DataSpecificRegistrationInfo.class.getClassLoader());
         mNrState = source.readInt();
     }
 
@@ -389,16 +391,16 @@
      * @hide
      */
     @Nullable
-    public VoiceSpecificRegistrationStates getVoiceSpecificStates() {
-        return mVoiceSpecificStates;
+    public VoiceSpecificRegistrationInfo getVoiceSpecificInfo() {
+        return mVoiceSpecificInfo;
     }
 
     /**
      * @return Data registration related info
      */
     @Nullable
-    public DataSpecificRegistrationStates getDataSpecificStates() {
-        return mDataSpecificStates;
+    public DataSpecificRegistrationInfo getDataSpecificInfo() {
+        return mDataSpecificInfo;
     }
 
     @Override
@@ -474,8 +476,8 @@
                         ? mAvailableServices.stream().map(type -> serviceTypeToString(type))
                         .collect(Collectors.joining(",")) : null) + "]")
                 .append(" cellIdentity=").append(mCellIdentity)
-                .append(" voiceSpecificStates=").append(mVoiceSpecificStates)
-                .append(" dataSpecificStates=").append(mDataSpecificStates)
+                .append(" voiceSpecificInfo=").append(mVoiceSpecificInfo)
+                .append(" dataSpecificInfo=").append(mDataSpecificInfo)
                 .append(" nrState=").append(nrStateToString(mNrState))
                 .append("}").toString();
     }
@@ -484,7 +486,7 @@
     public int hashCode() {
         return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
                 mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
-                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrState);
+                mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState);
     }
 
     @Override
@@ -505,8 +507,8 @@
                 && mEmergencyOnly == other.mEmergencyOnly
                 && mAvailableServices.equals(other.mAvailableServices)
                 && Objects.equals(mCellIdentity, other.mCellIdentity)
-                && Objects.equals(mVoiceSpecificStates, other.mVoiceSpecificStates)
-                && Objects.equals(mDataSpecificStates, other.mDataSpecificStates)
+                && Objects.equals(mVoiceSpecificInfo, other.mVoiceSpecificInfo)
+                && Objects.equals(mDataSpecificInfo, other.mDataSpecificInfo)
                 && mNrState == other.mNrState;
     }
 
@@ -521,8 +523,8 @@
         dest.writeBoolean(mEmergencyOnly);
         dest.writeList(mAvailableServices);
         dest.writeParcelable(mCellIdentity, 0);
-        dest.writeParcelable(mVoiceSpecificStates, 0);
-        dest.writeParcelable(mDataSpecificStates, 0);
+        dest.writeParcelable(mVoiceSpecificInfo, 0);
+        dest.writeParcelable(mDataSpecificInfo, 0);
         dest.writeInt(mNrState);
     }
 
@@ -543,7 +545,7 @@
      *
      * @param state data specific registration state contains the 5G NR indicators.
      */
-    private void updateNrState(DataSpecificRegistrationStates state) {
+    private void updateNrState(DataSpecificRegistrationInfo state) {
         mNrState = NR_STATE_NONE;
         if (state.isEnDcAvailable) {
             if (!state.isDcNrRestricted && state.isNrAvailable) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index df31f50..a794ba1 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1132,7 +1132,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @TestApi
     public void setVoiceRoamingType(@RoamingType int type) {
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
@@ -1153,7 +1153,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @TestApi
     public void setDataRoamingType(@RoamingType int type) {
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
@@ -1855,6 +1855,7 @@
     /**
      * @hide
      */
+    @TestApi
     public void addNetworkRegistrationInfo(NetworkRegistrationInfo regState) {
         if (regState == null) return;
 
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ac11940..ee28ca2 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -32,6 +32,7 @@
 import android.graphics.Typeface;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.ParcelUuid;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
@@ -154,11 +155,11 @@
     private boolean mIsOpportunistic;
 
     /**
-     * A UUID assigned to the subscription group. It returns
-     * null if not assigned.
+     * A UUID assigned to the subscription group. It returns null if not assigned.
+     * Check {@link SubscriptionManager#createSubscriptionGroup(List)} for more details.
      */
     @Nullable
-    private String mGroupUUID;
+    private ParcelUuid mGroupUUID;
 
     /**
      * Whether group of the subscription is disabled.
@@ -237,7 +238,7 @@
         this.mCardString = cardString;
         this.mCardId = cardId;
         this.mIsOpportunistic = isOpportunistic;
-        this.mGroupUUID = groupUUID;
+        this.mGroupUUID = groupUUID == null ? null : ParcelUuid.fromString(groupUUID);
         this.mIsGroupDisabled = isGroupDisabled;
         this.mCarrierId = carrierId;
         this.mProfileClass = profileClass;
@@ -461,7 +462,7 @@
      * @return group UUID a String of group UUID if it belongs to a group. Otherwise
      * it will return null.
      */
-    public @Nullable String getGroupUuid() {
+    public @Nullable ParcelUuid getGroupUuid() {
         return mGroupUUID;
     }
 
@@ -643,7 +644,7 @@
         dest.writeString(mCardString);
         dest.writeInt(mCardId);
         dest.writeBoolean(mIsOpportunistic);
-        dest.writeString(mGroupUUID);
+        dest.writeString(mGroupUUID == null ? null : mGroupUUID.toString());
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
         dest.writeInt(mProfileClass);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2edef83..14eac87 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -50,11 +50,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelUuid;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
-import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 
@@ -1752,6 +1753,10 @@
         Rlog.d(LOG_TAG, msg);
     }
 
+    private static void loge(String msg) {
+        Rlog.e(LOG_TAG, msg);
+    }
+
     /**
      * Returns the system's default subscription id.
      *
@@ -1991,24 +1996,6 @@
     }
 
     /**
-     * If a default is set to subscription which is not active, this will reset that default back to
-     * an invalid subscription id, i.e. < 0.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void clearDefaultsForInactiveSubIds() {
-        if (VDBG) logd("clearDefaultsForInactiveSubIds");
-        try {
-            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
-            if (iSub != null) {
-                iSub.clearDefaultsForInactiveSubIds();
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
      * Check if the supplied subscription ID is valid.
      *
      * <p>A valid subscription ID is not necessarily an active subscription ID
@@ -2740,11 +2727,20 @@
 
     /**
      * Inform SubscriptionManager that subscriptions in the list are bundled
-     * as a group. Typically it's a primary subscription and an opportunistic
-     * subscription. It should only affect multi-SIM scenarios where primary
-     * and opportunistic subscriptions can be activated together.
-     * Being in the same group means they might be activated or deactivated
-     * together, some of them may be invisible to the users, etc.
+     * as a group. It can be multiple primary (non-opportunistic) subscriptions,
+     * or one or more primary plus one or more opportunistic subscriptions.
+     *
+     * This API will always create a new immutable group and assign group UUID to all the
+     * subscriptions, regardless whether they are in a group already or not.
+     *
+     * Grouped subscriptions will have below behaviors:
+     * 1) They will share the same user settings.
+     * 2) The opportunistic subscriptions in the group is considered invisible and will not
+     *    return from {@link #getActiveSubscriptionInfoList()}, unless caller has carrier
+     *    privilege permission of the subscriptions.
+     * 3) The opportunistic subscriptions in the group can't be active by itself. If all other
+     *    non-opportunistic ones are deactivated (unplugged or disabled in Settings),
+     *    the opportunistic ones will be deactivated automatically.
      *
      * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
      * permission or had carrier privilege permission on the subscriptions:
@@ -2755,34 +2751,42 @@
      *             outlined above.
      *
      * @param subIdList list of subId that will be in the same group
-     * @return groupUUID a UUID assigned to the subscription group. It returns
-     * null if fails.
+     * @return groupUUID a UUID assigned to the subscription group.
      *
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public @Nullable String setSubscriptionGroup(@NonNull int[] subIdList) {
+    public @NonNull ParcelUuid createSubscriptionGroup(@NonNull List<Integer> subIdList) {
+        Preconditions.checkNotNull(subIdList, "can't create group for null subId list");
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (VDBG) {
-            logd("[setSubscriptionGroup]+ subIdList:" + Arrays.toString(subIdList));
+            logd("[createSubscriptionGroup]");
         }
 
-        String groupUUID = null;
+        ParcelUuid groupUuid = null;
+        int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                groupUUID = iSub.setSubscriptionGroup(subIdList, pkgForDebug);
+                groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
+            } else {
+                if (!isSystemProcess()) {
+                    throw new IllegalStateException("telephony service is null.");
+                }
             }
         } catch (RemoteException ex) {
-            // ignore it
+            loge("createSubscriptionGroup RemoteException " + ex);
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
         }
 
-        return groupUUID;
+        return groupUuid;
     }
 
     /**
-     * Remove a list of subscriptions from their subscription group.
-     * See {@link #setSubscriptionGroup(int[])} for more details.
+     * Add a list of subscriptions into a group.
+     * See {@link #createSubscriptionGroup(List)} for more details.
      *
      * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
      * permission or had carrier privilege permission on the subscriptions:
@@ -2791,34 +2795,97 @@
      *
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
+     * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist,
+     *             or the groupUuid doesn't exist.
      *
-     * @param subIdList list of subId that need removing from their groups.
-     * @return whether the operation succeeds.
+     * @param subIdList list of subId that need adding into the group
+     * @param groupUuid the groupUuid the subscriptions are being added to.
      *
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean removeSubscriptionsFromGroup(@NonNull int[] subIdList) {
+    public void addSubscriptionsIntoGroup(@NonNull List<Integer> subIdList,
+            @NonNull ParcelUuid groupUuid) {
+        Preconditions.checkNotNull(subIdList, "subIdList can't be null.");
+        Preconditions.checkNotNull(groupUuid, "groupUuid can't be null.");
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (VDBG) {
-            logd("[removeSubscriptionsFromGroup]+ subIdList:" + Arrays.toString(subIdList));
+            logd("[addSubscriptionsIntoGroup]");
         }
 
+        int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
+
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                return iSub.removeSubscriptionsFromGroup(subIdList, pkgForDebug);
+                iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
+            } else {
+                if (!isSystemProcess()) {
+                    throw new IllegalStateException("telephony service is null.");
+                }
             }
         } catch (RemoteException ex) {
-            // ignore it
+            loge("addSubscriptionsIntoGroup RemoteException " + ex);
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+    }
+
+    private boolean isSystemProcess() {
+        return Process.myUid() == Process.SYSTEM_UID;
+    }
+
+    /**
+     * Remove a list of subscriptions from their subscription group.
+     * See {@link #createSubscriptionGroup(List)} for more details.
+     *
+     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscriptions:
+     * {@link TelephonyManager#hasCarrierPrivileges()} or
+     * {@link #canManageSubscription(SubscriptionInfo)}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
+     *             the specified group.
+     *
+     * @param subIdList list of subId that need removing from their groups.
+     *
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void removeSubscriptionsFromGroup(@NonNull List<Integer> subIdList,
+            @NonNull ParcelUuid groupUuid) {
+        Preconditions.checkNotNull(subIdList, "subIdList can't be null.");
+        Preconditions.checkNotNull(groupUuid, "groupUuid can't be null.");
+        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        if (VDBG) {
+            logd("[removeSubscriptionsFromGroup]");
         }
 
-        return false;
+        int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
+            } else {
+                if (!isSystemProcess()) {
+                    throw new IllegalStateException("telephony service is null.");
+                }
+            }
+        } catch (RemoteException ex) {
+            loge("removeSubscriptionsFromGroup RemoteException " + ex);
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
     }
 
     /**
      * Get subscriptionInfo list of subscriptions that are in the same group of given subId.
-     * See {@link #setSubscriptionGroup(int[])} for more details.
+     * See {@link #createSubscriptionGroup(List)} for more details.
      *
      * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
      * permission or had carrier privilege permission on the subscription.
@@ -2827,28 +2894,35 @@
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
      *
-     * @param subId of which list of subInfo from the same group will be returned.
+     * @param groupUuid of which list of subInfo will be returned.
      * @return list of subscriptionInfo that belong to the same group, including the given
-     * subscription itself. It will return null if the subscription doesn't exist or it
-     * doesn't belong to any group.
+     * subscription itself. It will return an empty list if no subscription belongs to the group.
      *
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
-    public @Nullable List<SubscriptionInfo> getSubscriptionsInGroup(int subId) {
+    public @NonNull List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid) {
+        Preconditions.checkNotNull(groupUuid, "groupUuid can't be null");
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (VDBG) {
-            logd("[getSubscriptionsInGroup]+ subId:" + subId);
+            logd("[getSubscriptionsInGroup]+ groupUuid:" + groupUuid);
         }
 
         List<SubscriptionInfo> result = null;
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSubscriptionsInGroup(subId, pkgForDebug);
+                result = iSub.getSubscriptionsInGroup(groupUuid, pkgForDebug);
+            } else {
+                if (!isSystemProcess()) {
+                    throw new IllegalStateException("telephony service is null.");
+                }
             }
         } catch (RemoteException ex) {
-            // ignore it
+            loge("removeSubscriptionsFromGroup RemoteException " + ex);
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
         }
 
         return result;
@@ -2868,7 +2942,7 @@
         if (info == null) return false;
 
         // If subscription is NOT grouped opportunistic subscription, it's visible.
-        if (TextUtils.isEmpty(info.getGroupUuid()) || !info.isOpportunistic()) return true;
+        if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;
 
         // If the caller is the carrier app and owns the subscription, it should be visible
         // to the caller.
@@ -2898,14 +2972,14 @@
             // It should be the current active primary subscription if any, or any
             // primary subscription.
             List<SubscriptionInfo> selectableList = new ArrayList<>();
-            Map<String, SubscriptionInfo> groupMap = new HashMap<>();
+            Map<ParcelUuid, SubscriptionInfo> groupMap = new HashMap<>();
 
             for (SubscriptionInfo info : availableList) {
                 // Opportunistic subscriptions are considered invisible
                 // to users so they should never be returned.
                 if (!isSubscriptionVisible(info)) continue;
 
-                String groupUuid = info.getGroupUuid();
+                ParcelUuid groupUuid = info.getGroupUuid();
                 if (groupUuid == null) {
                     // Doesn't belong to any group. Add in the list.
                     selectableList.add(info);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d296b2f..5df7bf7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1428,6 +1428,70 @@
     public static final String EXTRA_ANOMALY_DESCRIPTION =
             "android.telephony.extra.ANOMALY_DESCRIPTION";
 
+    /**
+     * Broadcast intent sent to indicate primary (non-opportunistic) subscription list has changed.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED =
+            "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED";
+
+    /**
+     * Integer intent extra to be used with {@link #ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED}
+     * to indicate whether a SIM selection is needed to choose default subscription.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE =
+            "android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
+
+    /**
+     * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+     * to indicate there's no need to re-select any default subscription.
+     * @hide
+     */
+    public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE = 0;
+
+    /**
+     * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+     * to indicate there's a need to select default data subscription.
+     * @hide
+     */
+    public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA = 1;
+
+    /**
+     * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+     * to indicate there's a need to select default voice call subscription.
+     * @hide
+     */
+    public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_VOICE = 2;
+
+    /**
+     * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+     * to indicate there's a need to select default sms subscription.
+     * @hide
+     */
+    public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_SMS = 3;
+
+    /**
+     * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+     * to indicate user to decide whether current SIM should be preferred for all
+     * data / voice / sms.
+     * @hide
+     */
+    public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_FOR_ALL_TYPES = 4;
+
+    /**
+     * Integer intent extra to be used with
+     * {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_FOR_ALL_TYPES}
+     * to indicate which SIM is being selected.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DEFAULT_SUBSCRIPTION_ID =
+            "android.telephony.extra.DEFAULT_SUBSCRIPTION_ID";
+
     //
     //
     // Device Info
@@ -7018,6 +7082,35 @@
     }
 
     /**
+     * Query Telephony to see if there has recently been an emergency SMS sent to the network by the
+     * user and we are still within the time interval after the emergency SMS was sent that we are
+     * considered in Emergency SMS mode.
+     *
+     * <p>This mode is used by other applications to allow them to perform special functionality,
+     * such as allow the GNSS service to provide user location to the carrier network for emergency
+     * when an emergency SMS is sent. This interval is set by
+     * {@link CarrierConfigManager#KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT}. If
+     * the carrier does not support this mode, this function will always return false.
+     *
+     * @return true if this device is in emergency SMS mode, false otherwise.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isInEmergencySmsMode() {
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isInEmergencySmsMode();
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getNetworkSelectionMode RemoteException", ex);
+        }
+        return false;
+    }
+
+    /**
      * Set the preferred network type.
      *
      * <p>Requires Permission:
diff --git a/telephony/java/android/telephony/VoiceSpecificRegistrationStates.java b/telephony/java/android/telephony/VoiceSpecificRegistrationInfo.java
similarity index 63%
rename from telephony/java/android/telephony/VoiceSpecificRegistrationStates.java
rename to telephony/java/android/telephony/VoiceSpecificRegistrationInfo.java
index d8ce5b4..18a533a 100644
--- a/telephony/java/android/telephony/VoiceSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/VoiceSpecificRegistrationInfo.java
@@ -1,5 +1,22 @@
+/*
+ * Copyright 2018 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.telephony;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -10,14 +27,14 @@
  * Class that stores information specific to voice network registration.
  * @hide
  */
-public class VoiceSpecificRegistrationStates implements Parcelable{
+public class VoiceSpecificRegistrationInfo implements Parcelable{
     /**
      * oncurrent services support indicator. if
      * registered on a CDMA system.
      * false - Concurrent services not supported,
      * true - Concurrent services supported
      */
-     public final boolean cssSupported;
+    public final boolean cssSupported;
 
     /**
      * TSB-58 Roaming Indicator if registered
@@ -40,15 +57,15 @@
      */
     public final int defaultRoamingIndicator;
 
-    VoiceSpecificRegistrationStates(boolean cssSupported, int roamingIndicator, int systemIsInPrl,
-            int defaultRoamingIndicator) {
+    VoiceSpecificRegistrationInfo(boolean cssSupported, int roamingIndicator, int systemIsInPrl,
+                                  int defaultRoamingIndicator) {
         this.cssSupported = cssSupported;
         this.roamingIndicator = roamingIndicator;
         this.systemIsInPrl = systemIsInPrl;
         this.defaultRoamingIndicator = defaultRoamingIndicator;
     }
 
-    private VoiceSpecificRegistrationStates(Parcel source) {
+    private VoiceSpecificRegistrationInfo(Parcel source) {
         this.cssSupported = source.readBoolean();
         this.roamingIndicator = source.readInt();
         this.systemIsInPrl = source.readInt();
@@ -70,7 +87,7 @@
 
     @Override
     public String toString() {
-        return "VoiceSpecificRegistrationStates {"
+        return "VoiceSpecificRegistrationInfo {"
                 + " mCssSupported=" + cssSupported
                 + " mRoamingIndicator=" + roamingIndicator
                 + " mSystemIsInPrl=" + systemIsInPrl
@@ -87,11 +104,11 @@
     public boolean equals(Object o) {
         if (this == o) return true;
 
-        if (o == null || !(o instanceof VoiceSpecificRegistrationStates)) {
+        if (o == null || !(o instanceof VoiceSpecificRegistrationInfo)) {
             return false;
         }
 
-        VoiceSpecificRegistrationStates other = (VoiceSpecificRegistrationStates) o;
+        VoiceSpecificRegistrationInfo other = (VoiceSpecificRegistrationInfo) o;
         return this.cssSupported == other.cssSupported
                 && this.roamingIndicator == other.roamingIndicator
                 && this.systemIsInPrl == other.systemIsInPrl
@@ -99,16 +116,16 @@
     }
 
 
-    public static final @android.annotation.NonNull Parcelable.Creator<VoiceSpecificRegistrationStates> CREATOR =
-            new Parcelable.Creator<VoiceSpecificRegistrationStates>() {
+    public static final @NonNull Parcelable.Creator<VoiceSpecificRegistrationInfo> CREATOR =
+            new Parcelable.Creator<VoiceSpecificRegistrationInfo>() {
                 @Override
-                public VoiceSpecificRegistrationStates createFromParcel(Parcel source) {
-                    return new VoiceSpecificRegistrationStates(source);
+                public VoiceSpecificRegistrationInfo createFromParcel(Parcel source) {
+                    return new VoiceSpecificRegistrationInfo(source);
                 }
 
                 @Override
-                public VoiceSpecificRegistrationStates[] newArray(int size) {
-                    return new VoiceSpecificRegistrationStates[size];
+                public VoiceSpecificRegistrationInfo[] newArray(int size) {
+                    return new VoiceSpecificRegistrationInfo[size];
                 }
             };
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index d2b4133..5e3f398 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -210,7 +210,7 @@
     /**
      * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask.
      * @hide
-     * @deprecated
+     * @deprecated Use {@link MmTelFeature.MmTelCapabilities} instead.
      */
     @SystemApi  // SystemApi only because it was leaked through type usage in a previous release.
     public static class Capabilities {
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 3bbf7a4..01fdae8 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.telephony.SubscriptionInfo;
+import android.os.ParcelUuid;
 import com.android.internal.telephony.ISetOpportunisticDataCallback;
 
 interface ISub {
@@ -202,7 +203,7 @@
      * null if fails.
      *
      */
-    String setSubscriptionGroup(in int[] subIdList, String callingPackage);
+    ParcelUuid createSubscriptionGroup(in int[] subIdList, String callingPackage);
 
     /**
      * Set which subscription is preferred for cellular data. It's
@@ -234,9 +235,13 @@
      */
     List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage);
 
-    boolean removeSubscriptionsFromGroup(in int[] subIdList, String callingPackage);
+    void removeSubscriptionsFromGroup(in int[] subIdList, in ParcelUuid groupUuid,
+        String callingPackage);
 
-    List<SubscriptionInfo> getSubscriptionsInGroup(int subId, String callingPackage);
+    void addSubscriptionsIntoGroup(in int[] subIdList, in ParcelUuid groupUuid,
+        String callingPackage);
+
+    List<SubscriptionInfo> getSubscriptionsInGroup(in ParcelUuid groupUuid, String callingPackage);
 
     int getSlotIndex(int subId);
 
@@ -264,8 +269,6 @@
 
     void setDefaultSmsSubId(int subId);
 
-    void clearDefaultsForInactiveSubIds();
-
     int[] getActiveSubIdList(boolean visibleOnly);
 
     int setSubscriptionProperty(int subId, String propKey, String propValue);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 10cc99e..d98f8d8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1707,6 +1707,11 @@
      */
      int getNetworkSelectionMode(int subId);
 
+     /**
+     * Return true if the device is in emergency sms mode, false otherwise.
+     */
+     boolean isInEmergencySmsMode();
+
     /**
      * Get a list of SMS apps on a user.
      */
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index 6765316..a87e2f5 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -3,6 +3,7 @@
 
   public class MockContext extends android.content.Context {
     method public android.view.Display getDisplay();
+    method public int getDisplayId();
   }
 
   @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 5725f0c..4ce4406 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -31,6 +31,7 @@
     shared_libs: [
         "libstats_proto_host",
         "libprotobuf-cpp-full",
+        "libbase",
     ],
 
     proto: {
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index a8d970e..e66ead7 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -49,7 +49,9 @@
       exclusiveField(that.exclusiveField),
       uidField(that.uidField),
       whitelisted(that.whitelisted),
-      binaryFields(that.binaryFields) {}
+      binaryFields(that.binaryFields),
+      hasModule(that.hasModule),
+      moduleName(that.moduleName) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -391,7 +393,12 @@
     AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
 
     if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
-      atomDecl.whitelisted = true;
+        atomDecl.whitelisted = true;
+    }
+
+    if (atomField->options().HasExtension(os::statsd::log_from_module)) {
+        atomDecl.hasModule = true;
+        atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module);
     }
 
     vector<java_type_t> signature;
@@ -399,25 +406,49 @@
     if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
         errorCount++;
     }
-    atoms->signatures.insert(signature);
+
+    // Add the signature if does not already exist.
+    auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
+    if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
+        set<string> modules;
+        if (atomDecl.hasModule) {
+            modules.insert(atomDecl.moduleName);
+        }
+        atoms->signatures_to_modules[signature] = modules;
+    } else {
+        if (atomDecl.hasModule) {
+            signature_to_modules_it->second.insert(atomDecl.moduleName);
+        }
+    }
     atoms->decls.insert(atomDecl);
 
     AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
     vector<java_type_t> nonChainedSignature;
     if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        atoms->non_chained_signatures.insert(nonChainedSignature);
+        auto it = atoms->non_chained_signatures_to_modules.find(signature);
+        if (it == atoms->non_chained_signatures_to_modules.end()) {
+            set<string> modules_non_chained;
+            if (atomDecl.hasModule) {
+                modules_non_chained.insert(atomDecl.moduleName);
+            }
+            atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
+        } else {
+            if (atomDecl.hasModule) {
+                it->second.insert(atomDecl.moduleName);
+            }
+        }
         atoms->non_chained_decls.insert(nonChainedAtomDecl);
     }
   }
 
   if (dbg) {
     printf("signatures = [\n");
-    for (set<vector<java_type_t>>::const_iterator it =
-             atoms->signatures.begin();
-         it != atoms->signatures.end(); it++) {
+    for (map<vector<java_type_t>, set<string>>::const_iterator it =
+             atoms->signatures_to_modules.begin();
+         it != atoms->signatures_to_modules.end(); it++) {
       printf("   ");
-      for (vector<java_type_t>::const_iterator jt = it->begin();
-           jt != it->end(); jt++) {
+      for (vector<java_type_t>::const_iterator jt = it->first.begin();
+           jt != it->first.end(); jt++) {
         printf(" %d", (int)*jt);
       }
       printf("\n");
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 6b86b862..44746c9 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -93,6 +93,9 @@
 
     vector<int> binaryFields;
 
+    bool hasModule = false;
+    string moduleName;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
@@ -104,10 +107,10 @@
 };
 
 struct Atoms {
-    set<vector<java_type_t>> signatures;
+    map<vector<java_type_t>, set<string>> signatures_to_modules;
     set<AtomDecl> decls;
     set<AtomDecl> non_chained_decls;
-    set<vector<java_type_t>> non_chained_signatures;
+    map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules;
 };
 
 /**
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 0270c72..daee6d6 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -12,6 +12,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "android-base/strings.h"
+
 using namespace google::protobuf;
 using namespace std;
 
@@ -20,6 +22,10 @@
 
 int maxPushedAtomId = 2;
 
+const string DEFAULT_MODULE_NAME = "DEFAULT";
+const string DEFAULT_CPP_NAMESPACE = "android,util";
+const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+
 using android::os::statsd::Atom;
 
 /**
@@ -97,40 +103,27 @@
     }
 }
 
-static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
-                               const AtomDecl &attributionDecl) {
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
+static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) {
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        return true;
+    }
+    return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+}
 
-    fprintf(out, "#include <mutex>\n");
-    fprintf(out, "#include <chrono>\n");
-    fprintf(out, "#include <thread>\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out, "#include <cutils/properties.h>\n");
-    fprintf(out, "#endif\n");
-    fprintf(out, "#include <stats_event_list.h>\n");
-    fprintf(out, "#include <log/log.h>\n");
-    fprintf(out, "#include <statslog.h>\n");
-    fprintf(out, "#include <utils/SystemClock.h>\n");
-    fprintf(out, "\n");
+static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        return true;
+    }
+    return modules.find(moduleName) != modules.end();
+}
 
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "namespace util {\n");
-    fprintf(out, "// the single event tag id for all stats logs\n");
-    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
-    fprintf(out, "#else\n");
-    fprintf(out, "const static bool kStatsdEnabled = false;\n");
-    fprintf(out, "#endif\n");
-
+static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
     std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
-                                             "audio_state_changed",
-                                             "call_state_changed",
-                                             "phone_signal_strength_changed",
-                                             "mobile_bytes_transfer_by_fg_bg",
-                                             "mobile_bytes_transfer"};
+                                                 "audio_state_changed",
+                                                 "call_state_changed",
+                                                 "phone_signal_strength_changed",
+                                                 "mobile_bytes_transfer_by_fg_bg",
+                                                 "mobile_bytes_transfer"};
     fprintf(out,
             "const std::set<int> "
             "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
@@ -256,6 +249,56 @@
             "const std::map<int, std::vector<int>> "
             "AtomsInfo::kBytesFieldAtoms = "
             "getBinaryFieldAtoms();\n");
+}
+
+// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+void write_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (string cppNamespace : cppNamespaceVec) {
+        fprintf(out, "namespace %s {\n", cppNamespace.c_str());
+    }
+}
+
+// Writes namespace closing brackets for cpp and header files.
+void write_closing_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
+        fprintf(out, "} // namespace %s\n", it->c_str());
+    }
+}
+
+static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
+                               const string& moduleName, const string& cppNamespace,
+                               const string& importHeader) {
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "#include <mutex>\n");
+    fprintf(out, "#include <chrono>\n");
+    fprintf(out, "#include <thread>\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
+    fprintf(out, "#include <cutils/properties.h>\n");
+    fprintf(out, "#endif\n");
+    fprintf(out, "#include <stats_event_list.h>\n");
+    fprintf(out, "#include <log/log.h>\n");
+    fprintf(out, "#include <%s>\n", importHeader.c_str());
+    fprintf(out, "#include <utils/SystemClock.h>\n");
+    fprintf(out, "\n");
+
+    write_namespace(out, cppNamespace);
+    fprintf(out, "// the single event tag id for all stats logs\n");
+    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
+    fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
+    fprintf(out, "#else\n");
+    fprintf(out, "const static bool kStatsdEnabled = false;\n");
+    fprintf(out, "#endif\n");
+
+    // AtomsInfo is only used by statsd internally and is not needed for other modules.
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        write_atoms_info_cpp(out, atoms);
+    }
 
     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
@@ -263,15 +306,19 @@
 
     // Print write methods
     fprintf(out, "\n");
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-        signature != atoms.signatures.end(); signature++) {
+    for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+        signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+        vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex;
 
         fprintf(out, "int\n");
         fprintf(out, "try_stats_write(int32_t code");
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -303,8 +350,8 @@
         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
         fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (const auto &chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -387,15 +434,19 @@
         fprintf(out, "\n");
     }
 
-   for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-       signature != atoms.signatures.end(); signature++) {
+   for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+       signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+       if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+           continue;
+       }
+       vector<java_type_t> signature = signature_to_modules_it->first;
        int argIndex;
 
        fprintf(out, "int\n");
        fprintf(out, "stats_write(int32_t code");
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                for (auto chainField : attributionDecl.fields) {
                    if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -429,8 +480,8 @@
        fprintf(out, "      ret =  try_stats_write(code");
 
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                for (auto chainField : attributionDecl.fields) {
                    if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -468,15 +519,19 @@
        fprintf(out, "\n");
    }
 
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
-        signature != atoms.non_chained_signatures.end(); signature++) {
+    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+        if (!signature_needed_for_module(signature_it->second, moduleName)) {
+            continue;
+        }
+        vector<java_type_t> signature = signature_it->first;
         int argIndex;
 
         fprintf(out, "int\n");
         fprintf(out, "try_stats_write_non_chained(int32_t code");
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             argIndex++;
         }
@@ -488,8 +543,8 @@
         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
         fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (argIndex == 1) {
                 fprintf(out, "    event.begin();\n\n");
                 fprintf(out, "    event.begin();\n");
@@ -522,15 +577,19 @@
         fprintf(out, "\n");
     }
 
-   for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
-       signature != atoms.non_chained_signatures.end(); signature++) {
+    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+       if (!signature_needed_for_module(signature_it->second, moduleName)) {
+           continue;
+       }
+       vector<java_type_t> signature = signature_it->first;
        int argIndex;
 
        fprintf(out, "int\n");
        fprintf(out, "stats_write_non_chained(int32_t code");
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
            argIndex++;
        }
@@ -543,8 +602,8 @@
        fprintf(out, "      ret =  try_stats_write_non_chained(code");
 
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            fprintf(out, ", arg%d",   argIndex);
            argIndex++;
        }
@@ -572,8 +631,7 @@
 
     // Print footer
     fprintf(out, "\n");
-    fprintf(out, "} // namespace util\n");
-    fprintf(out, "} // namespace android\n");
+    write_closing_namespace(out, cppNamespace);
 
     return 0;
 }
@@ -623,14 +681,23 @@
 }
 
 static void write_cpp_method_header(
-    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
-    const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+        FILE* out,
+        const string& method_name,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl, const string& moduleName) {
+
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        // Skip if this signature is not needed for the module.
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "int %s(int32_t code", method_name.c_str());
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -659,7 +726,8 @@
 }
 
 static int
-write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+        const string& moduleName, const string& cppNamespace)
 {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
@@ -672,8 +740,7 @@
     fprintf(out, "#include <set>\n");
     fprintf(out, "\n");
 
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "namespace util {\n");
+    write_namespace(out, cppNamespace);
     fprintf(out, "\n");
     fprintf(out, "/*\n");
     fprintf(out, " * API For logging statistics events.\n");
@@ -691,6 +758,10 @@
     // Print atom constants
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
         string constant = make_constant_name(atom->name);
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
@@ -720,6 +791,11 @@
     fprintf(out, "//\n\n");
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
+
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
             field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ENUM) {
@@ -747,47 +823,51 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
-    fprintf(out, "struct StateAtomFieldOptions {\n");
-    fprintf(out, "  std::vector<int> primaryFields;\n");
-    fprintf(out, "  int exclusiveField;\n");
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
+    // This metadata is only used by statsd, which uses the default libstatslog.
+    if (moduleName == DEFAULT_MODULE_NAME) {
 
-    fprintf(out, "struct AtomsInfo {\n");
-    fprintf(out,
-            "  const static std::set<int> "
-            "kNotTruncatingTimestampAtomWhiteList;\n");
-    fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
-    fprintf(out,
-            "  const static std::set<int> kAtomsWithAttributionChain;\n");
-    fprintf(out,
-            "  const static std::map<int, StateAtomFieldOptions> "
-            "kStateAtomsFieldOptions;\n");
-    fprintf(out,
-            "  const static std::map<int, std::vector<int>> "
-            "kBytesFieldAtoms;");
-    fprintf(out,
-            "  const static std::set<int> kWhitelistedAtoms;\n");
-    fprintf(out, "};\n");
+        fprintf(out, "struct StateAtomFieldOptions {\n");
+        fprintf(out, "  std::vector<int> primaryFields;\n");
+        fprintf(out, "  int exclusiveField;\n");
+        fprintf(out, "};\n");
+        fprintf(out, "\n");
 
-    fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
-            maxPushedAtomId);
+        fprintf(out, "struct AtomsInfo {\n");
+        fprintf(out,
+                "  const static std::set<int> "
+                "kNotTruncatingTimestampAtomWhiteList;\n");
+        fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
+        fprintf(out,
+                "  const static std::set<int> kAtomsWithAttributionChain;\n");
+        fprintf(out,
+                "  const static std::map<int, StateAtomFieldOptions> "
+                "kStateAtomsFieldOptions;\n");
+        fprintf(out,
+                "  const static std::map<int, std::vector<int>> "
+                "kBytesFieldAtoms;");
+        fprintf(out,
+                "  const static std::set<int> kWhitelistedAtoms;\n");
+        fprintf(out, "};\n");
+
+        fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
+                maxPushedAtomId);
+    }
 
     // Print write methods
     fprintf(out, "//\n");
     fprintf(out, "// Write methods\n");
     fprintf(out, "//\n");
-    write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
+    write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
+            moduleName);
 
     fprintf(out, "//\n");
     fprintf(out, "// Write flattened methods\n");
     fprintf(out, "//\n");
-    write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
-        attributionDecl);
+    write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
+        attributionDecl, moduleName);
 
     fprintf(out, "\n");
-    fprintf(out, "} // namespace util\n");
-    fprintf(out, "} // namespace android\n");
+    write_closing_namespace(out, cppNamespace);
 
     return 0;
 }
@@ -812,15 +892,19 @@
 }
 
 static void write_java_method(
-    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
-    const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-        signature != signatures.end(); signature++) {
+        FILE* out,
+        const string& method_name,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
+
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static native int %s(int code", method_name.c_str());
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     fprintf(out, ", %s[] %s",
@@ -837,15 +921,17 @@
     }
 }
 
-static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
+static void write_java_work_source_method(FILE* out,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
     fprintf(out, "\n    // WorkSource methods.\n");
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         // Determine if there is Attribution in this signature.
         int attributionArg = -1;
         int argIndexMax = 0;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             argIndexMax++;
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 if (attributionArg > -1) {
@@ -865,8 +951,8 @@
         fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 fprintf(out, ", WorkSource ws");
             } else {
@@ -974,9 +1060,10 @@
 
     // Print write methods
     fprintf(out, "    // Write methods\n");
-    write_java_method(out, "write", atoms.signatures, attributionDecl);
-    write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
-    write_java_work_source_method(out, atoms.signatures);
+    write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
+    write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+            attributionDecl);
+    write_java_work_source_method(out, atoms.signatures_to_modules);
 
     fprintf(out, "}\n");
 
@@ -1154,19 +1241,20 @@
 
 static int
 write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
-    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
-{
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
     // Print write methods
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-        signature != signatures.end(); signature++) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex;
 
         fprintf(out, "static int\n");
         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
-                jni_function_name(java_method_name, *signature).c_str());
+                jni_function_name(java_method_name, signature).c_str());
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
@@ -1187,8 +1275,8 @@
         argIndex = 1;
         bool hadStringOrChain = false;
         bool isKeyValuePairAtom = false;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_STRING) {
                 hadStringOrChain = true;
                 fprintf(out, "    const char* str%d;\n", argIndex);
@@ -1288,8 +1376,8 @@
         argIndex = 1;
         fprintf(out, "\n    int ret =  android::util::%s(code",
                 cpp_method_name.c_str());
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_INT) {
@@ -1316,8 +1404,8 @@
 
         // Clean up strings
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_STRING) {
                 fprintf(out, "    if (str%d != NULL) {\n", argIndex);
                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
@@ -1357,13 +1445,15 @@
 }
 
 void write_jni_registration(FILE* out, const string& java_method_name,
-    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
             java_method_name.c_str(),
-            jni_function_signature(*signature, attributionDecl).c_str(),
-            jni_function_name(java_method_name, *signature).c_str());
+            jni_function_signature(signature, attributionDecl).c_str(),
+            jni_function_name(java_method_name, signature).c_str());
     }
 }
 
@@ -1388,25 +1478,26 @@
     fprintf(out, "namespace android {\n");
     fprintf(out, "\n");
 
-    write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
+    write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
     write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
-        atoms.non_chained_signatures, attributionDecl);
+            atoms.non_chained_signatures_to_modules, attributionDecl);
 
     // Print registration function table
     fprintf(out, "/*\n");
     fprintf(out, " * JNI registration.\n");
     fprintf(out, " */\n");
     fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
-    write_jni_registration(out, "write", atoms.signatures, attributionDecl);
-    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
+    write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
+    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+            attributionDecl);
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
     // Print registration function
-    fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
+    fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
     fprintf(out, "    return RegisterMethodsOrDie(\n");
     fprintf(out, "            env,\n");
-    fprintf(out, "            \"android/util/StatsLog\",\n");
+    fprintf(out, "            \"android/util/StatsLogInternal\",\n");
     fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
     fprintf(out, "}\n");
 
@@ -1426,6 +1517,10 @@
     fprintf(stderr, "  --help               this message\n");
     fprintf(stderr, "  --java FILENAME      the java file to output\n");
     fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
+    fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
+    fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
+    fprintf(stderr, "                                    comma separated namespace of the files\n");
+    fprintf(stderr, "  --importHeader NAME  required for cpp/jni to say which header to import\n");
 }
 
 /**
@@ -1439,6 +1534,10 @@
     string javaFilename;
     string jniFilename;
 
+    string moduleName = DEFAULT_MODULE_NAME;
+    string cppNamespace = DEFAULT_CPP_NAMESPACE;
+    string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+
     int index = 1;
     while (index < argc) {
         if (0 == strcmp("--help", argv[index])) {
@@ -1472,6 +1571,27 @@
                 return 1;
             }
             jniFilename = argv[index];
+        } else if (0 == strcmp("--module", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            moduleName = argv[index];
+        } else if (0 == strcmp("--namespace", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            cppNamespace = argv[index];
+        } else if (0 == strcmp("--importHeader", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            cppHeaderImport = argv[index];
         }
         index++;
     }
@@ -1503,8 +1623,18 @@
             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
             return 1;
         }
+        // If this is for a specific module, the namespace must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+            fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+            return 1;
+        }
+        // If this is for a specific module, the header file to import must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
+            fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
+            return 1;
+        }
         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
-            out, atoms, attributionDecl);
+            out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
         fclose(out);
     }
 
@@ -1515,8 +1645,12 @@
             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
             return 1;
         }
+        // If this is for a specific module, the namespace must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+            fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+        }
         errorCount = android::stats_log_api_gen::write_stats_log_header(
-            out, atoms, attributionDecl);
+            out, atoms, attributionDecl, moduleName, cppNamespace);
         fclose(out);
     }
 
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 24ebf4d..c3e70382 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -213,4 +213,24 @@
     // by whitelisted sources
     NonWhitelistedAtom non_whitelisted_atom = 2;
   }
+}
+
+message ModuleOneAtom {
+    optional int32 field = 1;
+}
+
+message ModuleTwoAtom {
+    optional int32 field = 1;
+}
+
+message NoModuleAtom {
+    optional string field = 1;
+}
+
+message ModuleAtoms {
+    oneof event {
+        ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"];
+        ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"];
+        NoModuleAtom no_module_atom = 3;
+    }
 }
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index dc585c1..bcf18ae 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -32,7 +32,7 @@
  * Return whether the set contains a vector of the elements provided.
  */
 static bool
-set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
+set_contains_vector(const map<vector<java_type_t>, set<string>>& s, int count, ...)
 {
     va_list args;
     vector<java_type_t> v;
@@ -86,17 +86,17 @@
     int errorCount = collate_atoms(Event::descriptor(), &atoms);
 
     EXPECT_EQ(0, errorCount);
-    EXPECT_EQ(3ul, atoms.signatures.size());
+    EXPECT_EQ(3ul, atoms.signatures_to_modules.size());
 
     // IntAtom, AnotherIntAtom
-    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
 
     // OutOfOrderAtom
-    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT);
 
     // AllTypesAtom
     EXPECT_SET_CONTAINS_SIGNATURE(
-        atoms.signatures,
+        atoms.signatures_to_modules,
         JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
         JAVA_TYPE_DOUBLE,            // double
         JAVA_TYPE_FLOAT,             // float
@@ -228,8 +228,7 @@
 
 TEST(CollationTest, PassOnWhitelistedAtom) {
     Atoms atoms;
-    int errorCount =
-            collate_atoms(ListedAtoms::descriptor(), &atoms);
+    int errorCount = collate_atoms(ListedAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
     EXPECT_EQ(atoms.decls.size(), 2ul);
 }
@@ -246,5 +245,46 @@
     }
 }
 
+TEST(CollationTest, PassOnLogFromModuleAtom) {
+    Atoms atoms;
+    int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+    EXPECT_EQ(errorCount, 0);
+    EXPECT_EQ(atoms.decls.size(), 3ul);
+}
+
+TEST(CollationTest, RecognizeModuleAtom) {
+    Atoms atoms;
+    int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+    EXPECT_EQ(errorCount, 0);
+    EXPECT_EQ(atoms.decls.size(), 3ul);
+    for (const auto& atomDecl: atoms.decls) {
+        if (atomDecl.code == 1) {
+            EXPECT_TRUE(atomDecl.hasModule);
+            EXPECT_EQ(atomDecl.moduleName, "module1");
+        } else if (atomDecl.code == 2) {
+            EXPECT_TRUE(atomDecl.hasModule);
+            EXPECT_EQ(atomDecl.moduleName, "module2");
+        } else {
+            EXPECT_FALSE(atomDecl.hasModule);
+        }
+    }
+
+    EXPECT_EQ(atoms.signatures_to_modules.size(), 2u);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING);
+    for (auto signature_to_modules_it : atoms.signatures_to_modules) {
+        vector<java_type_t> signature = signature_to_modules_it.first;
+        if (signature[0] == JAVA_TYPE_STRING) {
+            EXPECT_EQ(signature_to_modules_it.second.size(), 0u);
+        } else if (signature[0] == JAVA_TYPE_INT) {
+            set<string> modules = signature_to_modules_it.second;
+            EXPECT_EQ(modules.size(), 2u);
+            // Assert that the set contains "module1" and "module2".
+            EXPECT_NE(modules.find("module1"), modules.end());
+            EXPECT_NE(modules.find("module2"), modules.end());
+        }
+    }
+}
+
 }  // namespace stats_log_api_gen
 }  // namespace android
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 01176f2..e595164 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -345,7 +345,7 @@
     }
 
     /** Whether the primary registered cell of current entry is same as that of previous entry */
-    public boolean getIsSameRegisteredCell() {
+    public boolean isSameRegisteredCell() {
         return mIsSameRegisteredCell;
     }
 }
diff --git a/wifi/java/android/net/wifi/rtt/ResponderLocation.java b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
index 37d5f0a..e1d82f8 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderLocation.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
@@ -1169,6 +1169,8 @@
      * (see 802.11REVmc Section 11.12.3 - Registered STA Operation).
      * <p>
      * Only valid if {@link #isLciSubelementValid()} returns true, or will throw an exception.
+     *
+     * @hide
      */
     public boolean getRegisteredLocationDseIndication() {
         if (!mIsLciValid) {
@@ -1185,6 +1187,8 @@
      * (see 802.11REVmc Section 11.12.3 - Registered STA Operation).
      * <p>
      * Only valid if {@link #isLciSubelementValid()} returns true, or will throw an exception.
+     *
+     * @hide
      */
     public boolean getDependentStationIndication() {
         if (!mIsLciValid) {
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index cd60f02..5184152 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -116,6 +116,6 @@
         assertEquals(expected.getCellularSignalStrengthDbm(),
                 actual.getCellularSignalStrengthDbm());
         assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb());
-        assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell());
+        assertEquals(expected.isSameRegisteredCell(), actual.isSameRegisteredCell());
     }
 }