Merge "Show scrims when bouncer is on top of QS" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index a78bd2e..26fe641 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7278,7 +7278,6 @@
   public abstract class SliceProvider extends android.content.ContentProvider {
     ctor public SliceProvider();
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public final java.lang.String getBindingPackage();
     method public final java.lang.String getType(android.net.Uri);
     method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
     method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
@@ -24052,13 +24051,13 @@
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
     method public byte[] getEmbeddedPicture();
-    method public android.graphics.Bitmap getFrameAtIndex(int);
+    method public android.graphics.Bitmap getFrameAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
     method public android.graphics.Bitmap getFrameAtTime(long, int);
     method public android.graphics.Bitmap getFrameAtTime(long);
     method public android.graphics.Bitmap getFrameAtTime();
-    method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
-    method public android.graphics.Bitmap getImageAtIndex(int);
-    method public android.graphics.Bitmap getPrimaryImage();
+    method public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, android.media.MediaMetadataRetriever.BitmapParams);
+    method public android.graphics.Bitmap getImageAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
+    method public android.graphics.Bitmap getPrimaryImage(android.media.MediaMetadataRetriever.BitmapParams);
     method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
     method public void release();
     method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -24104,6 +24103,13 @@
     field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public static final class MediaMetadataRetriever.BitmapParams {
+    ctor public MediaMetadataRetriever.BitmapParams();
+    method public android.graphics.Bitmap.Config getActualConfig();
+    method public android.graphics.Bitmap.Config getPreferredConfig();
+    method public void setPreferredConfig(android.graphics.Bitmap.Config);
+  }
+
   public final class MediaMuxer {
     ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
     ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
@@ -24351,7 +24357,6 @@
     method public abstract android.media.MediaDrm.KeyRequest getDrmKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
     method public abstract java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
     method public abstract long getDuration();
-    method public abstract int getMediaPlayer2State();
     method public abstract android.os.PersistableBundle getMetrics();
     method public abstract android.media.PlaybackParams getPlaybackParams();
     method public abstract int getSelectedTrack(int);
@@ -24377,33 +24382,35 @@
     method public abstract void setPlaybackParams(android.media.PlaybackParams);
     method public abstract void setSurface(android.view.Surface);
     method public abstract void setSyncParams(android.media.SyncParams);
-    field public static final int MEDIAPLAYER2_STATE_ERROR = 5; // 0x5
-    field public static final int MEDIAPLAYER2_STATE_IDLE = 1; // 0x1
-    field public static final int MEDIAPLAYER2_STATE_PAUSED = 3; // 0x3
-    field public static final int MEDIAPLAYER2_STATE_PLAYING = 4; // 0x4
-    field public static final int MEDIAPLAYER2_STATE_PREPARED = 2; // 0x2
-    field public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1; // 0x1
-    field public static final int MEDIA_CALL_DESELECT_TRACK = 2; // 0x2
-    field public static final int MEDIA_CALL_LOOP_CURRENT = 3; // 0x3
-    field public static final int MEDIA_CALL_PAUSE = 4; // 0x4
-    field public static final int MEDIA_CALL_PLAY = 5; // 0x5
-    field public static final int MEDIA_CALL_PREPARE = 6; // 0x6
-    field public static final int MEDIA_CALL_RELEASE_DRM = 12; // 0xc
-    field public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13; // 0xd
-    field public static final int MEDIA_CALL_SEEK_TO = 14; // 0xe
-    field public static final int MEDIA_CALL_SELECT_TRACK = 15; // 0xf
-    field public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16; // 0x10
-    field public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17; // 0x11
-    field public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
-    field public static final int MEDIA_CALL_SET_DATA_SOURCE = 19; // 0x13
-    field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22; // 0x16
-    field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23; // 0x17
-    field public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24; // 0x18
-    field public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25; // 0x19
-    field public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26; // 0x1a
-    field public static final int MEDIA_CALL_SET_SURFACE = 27; // 0x1b
-    field public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28; // 0x1c
-    field public static final int MEDIA_CALL_SKIP_TO_NEXT = 29; // 0x1d
+    field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1
+    field public static final int CALL_COMPLETED_DESELECT_TRACK = 2; // 0x2
+    field public static final int CALL_COMPLETED_LOOP_CURRENT = 3; // 0x3
+    field public static final int CALL_COMPLETED_PAUSE = 4; // 0x4
+    field public static final int CALL_COMPLETED_PLAY = 5; // 0x5
+    field public static final int CALL_COMPLETED_PREPARE = 6; // 0x6
+    field public static final int CALL_COMPLETED_RELEASE_DRM = 12; // 0xc
+    field public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13; // 0xd
+    field public static final int CALL_COMPLETED_SEEK_TO = 14; // 0xe
+    field public static final int CALL_COMPLETED_SELECT_TRACK = 15; // 0xf
+    field public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16; // 0x10
+    field public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17; // 0x11
+    field public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
+    field public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19; // 0x13
+    field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22; // 0x16
+    field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23; // 0x17
+    field public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; // 0x18
+    field public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25; // 0x19
+    field public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26; // 0x1a
+    field public static final int CALL_COMPLETED_SET_SURFACE = 27; // 0x1b
+    field public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28; // 0x1c
+    field public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; // 0x1d
+    field public static final int CALL_STATUS_BAD_VALUE = 2; // 0x2
+    field public static final int CALL_STATUS_ERROR_IO = 4; // 0x4
+    field public static final int CALL_STATUS_ERROR_UNKNOWN = -2147483648; // 0x80000000
+    field public static final int CALL_STATUS_INVALID_OPERATION = 1; // 0x1
+    field public static final int CALL_STATUS_NO_DRM_SCHEME = 5; // 0x5
+    field public static final int CALL_STATUS_NO_ERROR = 0; // 0x0
+    field public static final int CALL_STATUS_PERMISSION_DENIED = 3; // 0x3
     field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14
     field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11
     field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8
@@ -24453,7 +24460,7 @@
 
   public static abstract class MediaPlayer2.MediaPlayer2EventCallback {
     ctor public MediaPlayer2.MediaPlayer2EventCallback();
-    method public void onCallComplete(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+    method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
     method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object);
     method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
     method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
@@ -43073,8 +43080,6 @@
     method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
-    method public int getAndroidCarrierIdForSubscription();
-    method public java.lang.CharSequence getAndroidCarrierNameForSubscription();
     method public int getCallState();
     method public android.os.PersistableBundle getCarrierConfig();
     method public deprecated android.telephony.CellLocation getCellLocation();
@@ -43105,6 +43110,8 @@
     method public int getPhoneType();
     method public android.telephony.ServiceState getServiceState();
     method public android.telephony.SignalStrength getSignalStrength();
+    method public int getSimCarrierId();
+    method public java.lang.CharSequence getSimCarrierIdName();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
     method public java.lang.String getSimOperatorName();
@@ -46625,8 +46632,8 @@
   }
 
   public final class DisplayCutout {
-    ctor public DisplayCutout(android.graphics.Rect, android.graphics.Region);
-    method public android.graphics.Region getBounds();
+    ctor public DisplayCutout(android.graphics.Rect, java.util.List<android.graphics.Rect>);
+    method public java.util.List<android.graphics.Rect> getBoundingRects();
     method public int getSafeInsetBottom();
     method public int getSafeInsetLeft();
     method public int getSafeInsetRight();
@@ -49700,9 +49707,9 @@
     field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf
     field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7
     field public static final int LAYOUT_CHANGED = 1; // 0x1
-    field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1
     field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0
     field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2
+    field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1
     field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100
     field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2
     field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
@@ -51069,7 +51076,8 @@
     method public java.lang.String getWidgetVersion();
   }
 
-  public final class SelectionEvent {
+  public final class SelectionEvent implements android.os.Parcelable {
+    method public int describeContents();
     method public long getDurationSincePreviousEvent();
     method public long getDurationSinceSessionStart();
     method public int getEnd();
@@ -51086,6 +51094,7 @@
     method public int getStart();
     method public java.lang.String getWidgetType();
     method public java.lang.String getWidgetVersion();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ABANDON = 107; // 0x6b
     field public static final int ACTION_COPY = 101; // 0x65
     field public static final int ACTION_CUT = 103; // 0x67
@@ -51097,6 +51106,7 @@
     field public static final int ACTION_SELECT_ALL = 200; // 0xc8
     field public static final int ACTION_SHARE = 104; // 0x68
     field public static final int ACTION_SMART_SHARE = 105; // 0x69
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.SelectionEvent> CREATOR;
     field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
     field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
     field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index ec7af51..43425cb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -717,7 +717,9 @@
   }
 
   public static final class UsageEvents.Event {
+    method public java.lang.String getNotificationChannelId();
     method public int getStandbyBucket();
+    field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
     field public static final int NOTIFICATION_SEEN = 10; // 0xa
     field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
   }
@@ -4708,6 +4710,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract void onClassifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
     method public abstract void onGenerateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
+    method public void onSelectionEvent(android.view.textclassifier.SelectionEvent);
     method public abstract void onSuggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
   }
@@ -6674,6 +6677,7 @@
     method public abstract android.view.View findFocus(android.view.View);
     method public abstract android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public abstract android.os.Handler getHandler(android.os.Handler);
+    method public default boolean isVisibleToUserForAutofill(int);
     method public abstract void onActivityResult(int, int, android.content.Intent);
     method public abstract void onAttachedToWindow();
     method public default boolean onCheckIsTextEditor();
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9bfbd38..8ba35b7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -23,6 +23,7 @@
 
 import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
 import "frameworks/base/core/proto/android/app/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -106,6 +107,9 @@
         KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64;
         AppDied app_died=65;
         ResourceConfigurationChanged resource_configuration_changed = 66;
+        BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67;
+        BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68;
+        BluetoothA2dpAudioStateChanged bluetooth_a2dp_audio_state_changed = 69;
         // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 
@@ -904,6 +908,63 @@
 }
 
 /**
+ * Logs when Bluetooth is enabled and disabled.
+ *
+ * Logged from:
+ *   services/core/java/com/android/server/BluetoothManagerService.java
+ */
+message BluetoothEnabledStateChanged {
+    repeated AttributionNode attribution_node = 1;
+    // Whether or not bluetooth is enabled on the device.
+    enum State {
+        UNKNOWN = 0;
+        ENABLED = 1;
+        DISABLED = 2;
+    }
+    optional State state = 2;
+    // The reason for being enabled/disabled.
+    // Eg. Airplane mode, crash, application request.
+    optional android.bluetooth.EnableDisableReasonEnum reason = 3;
+    // If the reason is an application request, this will be the package name.
+    optional string pkgName = 4;
+}
+
+/**
+ * Logs when a Bluetooth device connects and disconnects.
+ *
+ * Logged from:
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ */
+message BluetoothConnectionStateChanged {
+    // The state of the connection.
+    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+    optional android.bluetooth.ConnectionStateEnum state = 1;
+    // An identifier that can be used to match connect and disconnect events.
+    // Currently is last two bytes of a hash of a device level ID and
+    // the mac address of the bluetooth device that is connected.
+    optional int32 obfuscated_id = 2;
+    // The profile that is connected. Eg. GATT, A2DP, HEADSET.
+    // From android.bluetooth.BluetoothAdapter.java
+    optional int32 bt_profile = 3;
+}
+
+/**
+ * Logs when Bluetooth A2dp audio streaming state changes.
+ *
+ * Logged from:
+ *    TODO(b/73971848)
+ */
+message BluetoothA2dpAudioStateChanged {
+    // Whether or not audio is being played using Bluetooth A2dp.
+    enum State {
+        UNKNOWN = 0;
+        PLAY = 1;
+        STOP = 2;
+    }
+    optional State state = 1;
+}
+
+/**
  * Logs the duration of a davey (jank of >=700ms) when it occurs
  *
  * Logged from:
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 771d860..f134e54 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1006,6 +1006,7 @@
 Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid;
 Landroid/net/wifi/WifiConfiguration;->apBand:I
 Landroid/net/wifi/WifiConfiguration;->apChannel:I
+Landroid/net/wifi/WifiConfiguration;->defaultGwMacAddress:Ljava/lang/String;
 Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration;
 Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
 Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5687780..a1a10a5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -124,6 +124,7 @@
 import android.widget.Toolbar;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
@@ -7110,6 +7111,12 @@
         return mParent != null ? mParent.getActivityToken() : mToken;
     }
 
+    /** @hide */
+    @VisibleForTesting
+    public final ActivityThread getActivityThread() {
+        return mMainThread;
+    }
+
     final void performCreate(Bundle icicle) {
         performCreate(icicle, null);
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2d73ce0..a18ba71 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2101,15 +2101,17 @@
         private final int mOrientation;
         private final Rect mContentInsets;
         private final boolean mReducedResolution;
+        private final boolean mIsRealSnapshot;
         private final float mScale;
 
         public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets,
-                boolean reducedResolution, float scale) {
+                boolean reducedResolution, float scale, boolean isRealSnapshot) {
             mSnapshot = snapshot;
             mOrientation = orientation;
             mContentInsets = new Rect(contentInsets);
             mReducedResolution = reducedResolution;
             mScale = scale;
+            mIsRealSnapshot = isRealSnapshot;
         }
 
         private TaskSnapshot(Parcel source) {
@@ -2118,6 +2120,7 @@
             mContentInsets = source.readParcelable(null /* classLoader */);
             mReducedResolution = source.readBoolean();
             mScale = source.readFloat();
+            mIsRealSnapshot = source.readBoolean();
         }
 
         /**
@@ -2150,6 +2153,14 @@
         }
 
         /**
+         * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot
+         * due to the task having a secure window or having previews disabled.
+         */
+        public boolean isRealSnapshot() {
+            return mIsRealSnapshot;
+        }
+
+        /**
          * @return The scale this snapshot was taken in.
          */
         public float getScale() {
@@ -2168,13 +2179,15 @@
             dest.writeParcelable(mContentInsets, 0);
             dest.writeBoolean(mReducedResolution);
             dest.writeFloat(mScale);
+            dest.writeBoolean(mIsRealSnapshot);
         }
 
         @Override
         public String toString() {
             return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
                     + " mContentInsets=" + mContentInsets.toShortString()
-                    + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale;
+                    + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale
+                    + " mIsRealSnapshot=" + mIsRealSnapshot;
         }
 
         public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 379944e..afcd515 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3722,16 +3722,27 @@
         //Slog.i(TAG, "Running services: " + mServices);
     }
 
-    ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
+    ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
+            String reason) {
         ActivityClientRecord r = mActivities.get(token);
         if (localLOGV) Slog.v(TAG, "Performing resume of " + r
                 + " finished=" + r.activity.mFinished);
         if (r != null && !r.activity.mFinished) {
             if (r.getLifecycleState() == ON_RESUME) {
-                throw new IllegalStateException(
-                        "Trying to resume activity which is already resumed");
+                if (!finalStateRequest) {
+                    final RuntimeException e = new IllegalStateException(
+                            "Trying to resume activity which is already resumed");
+                    Slog.e(TAG, e.getMessage(), e);
+                    Slog.e(TAG, r.getStateString());
+                    // TODO(lifecycler): A double resume request is possible when an activity
+                    // receives two consequent transactions with relaunch requests and "resumed"
+                    // final state requests and the second relaunch is omitted. We still try to
+                    // handle two resume requests for the final state. For cases other than this
+                    // one, we don't expect it to happen.
+                }
+                return null;
             }
-            if (clearHide) {
+            if (finalStateRequest) {
                 r.hideForNow = false;
                 r.activity.mStartedActivity = false;
             }
@@ -3782,7 +3793,7 @@
     }
 
     @Override
-    public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
+    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
             String reason) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
@@ -3790,7 +3801,7 @@
         mSomeActivitiesChanged = true;
 
         // TODO Push resumeArgs into the activity for consideration
-        final ActivityClientRecord r = performResumeActivity(token, clearHide, reason);
+        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
 
         if (r != null) {
             final Activity a = r.activity;
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 6bc66ec..206495d 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -67,9 +67,16 @@
     public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
             int configChanges, PendingTransactionActions pendingActions, String reason);
 
-    /** Resume the activity. */
-    public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
-            String reason);
+    /**
+     * Resume the activity.
+     * @param token Target activity token.
+     * @param finalStateRequest Flag indicating if this call is handling final lifecycle state
+     *                          request for a transaction.
+     * @param isForward Flag indicating if next transition is forward.
+     * @param reason Reason for performing this operation.
+     */
+    public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
+            boolean isForward, String reason);
 
     /** Stop the activity. */
     public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index af2fb71..d16bc97 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -48,7 +48,8 @@
     public void execute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
-        client.handleResumeActivity(token, true /* clearHide */, mIsForward, "RESUME_ACTIVITY");
+        client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
+                "RESUME_ACTIVITY");
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 0e52b34..9e9a9c5 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -191,7 +191,7 @@
                     mTransactionHandler.handleStartActivity(r, mPendingActions);
                     break;
                 case ON_RESUME:
-                    mTransactionHandler.handleResumeActivity(r.token, false /* clearHide */,
+                    mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
                             r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                     break;
                 case ON_PAUSE:
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index df32fb9..aa2cf46 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -16,7 +16,6 @@
 package android.app.slice;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -35,7 +34,6 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.StrictMode.ThreadPolicy;
@@ -46,7 +44,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
@@ -163,18 +160,10 @@
 
     private static final boolean DEBUG = false;
 
-    private String mBindingPkg;
-    private SliceManager mSliceManager;
+    private static final long SLICE_BIND_ANR = 2000;
 
-    /**
-     * Return the package name of the caller that initiated the binding request
-     * currently happening. The returned package will have been
-     * verified to belong to the calling UID. Returns {@code null} if not
-     * currently performing an {@link #onBindSlice(Uri, List)}.
-     */
-    public final @Nullable String getBindingPackage() {
-        return mBindingPkg;
-    }
+    private String mCallback;
+    private SliceManager mSliceManager;
 
     @Override
     public void attachInfo(Context context, ProviderInfo info) {
@@ -183,12 +172,12 @@
     }
 
     /**
-     * Implemented to create a slice. Will be called on the main thread.
+     * Implemented to create a slice.
      * <p>
      * onBindSlice should return as quickly as possible so that the UI tied
      * to this slice can be responsive. No network or other IO will be allowed
      * during onBindSlice. Any loading that needs to be done should happen
-     * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+     * in the background with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
      * when the app is ready to provide the complete data in onBindSlice.
      * <p>
      * The slice returned should have a spec that is compatible with one of
@@ -381,55 +370,32 @@
     }
 
     private Collection<Uri> handleGetDescendants(Uri uri) {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
+        mCallback = "onGetSliceDescendants";
+        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+        try {
             return onGetSliceDescendants(uri);
-        } else {
-            CountDownLatch latch = new CountDownLatch(1);
-            Collection<Uri>[] output = new Collection[1];
-            Handler.getMain().post(() -> {
-                output[0] = onGetSliceDescendants(uri);
-                latch.countDown();
-            });
-            try {
-                latch.await();
-                return output[0];
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
+        } finally {
+            Handler.getMain().removeCallbacks(mAnr);
         }
     }
 
     private void handlePinSlice(Uri sliceUri) {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
+        mCallback = "onSlicePinned";
+        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+        try {
             onSlicePinned(sliceUri);
-        } else {
-            CountDownLatch latch = new CountDownLatch(1);
-            Handler.getMain().post(() -> {
-                onSlicePinned(sliceUri);
-                latch.countDown();
-            });
-            try {
-                latch.await();
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
+        } finally {
+            Handler.getMain().removeCallbacks(mAnr);
         }
     }
 
     private void handleUnpinSlice(Uri sliceUri) {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
+        mCallback = "onSliceUnpinned";
+        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+        try {
             onSliceUnpinned(sliceUri);
-        } else {
-            CountDownLatch latch = new CountDownLatch(1);
-            Handler.getMain().post(() -> {
-                onSliceUnpinned(sliceUri);
-                latch.countDown();
-            });
-            try {
-                latch.await();
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
+        } finally {
+            Handler.getMain().removeCallbacks(mAnr);
         }
     }
 
@@ -447,21 +413,12 @@
                 return createPermissionSlice(getContext(), sliceUri, pkg);
             }
         }
-        if (Looper.myLooper() == Looper.getMainLooper()) {
-            return onBindSliceStrict(sliceUri, supportedSpecs, pkg);
-        } else {
-            CountDownLatch latch = new CountDownLatch(1);
-            Slice[] output = new Slice[1];
-            Handler.getMain().post(() -> {
-                output[0] = onBindSliceStrict(sliceUri, supportedSpecs, pkg);
-                latch.countDown();
-            });
-            try {
-                latch.await();
-                return output[0];
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
+        mCallback = "onBindSlice";
+        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+        try {
+            return onBindSliceStrict(sliceUri, supportedSpecs);
+        } finally {
+            Handler.getMain().removeCallbacks(mAnr);
         }
     }
 
@@ -513,19 +470,21 @@
         }
     }
 
-    private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> supportedSpecs,
-            String callingPackage) {
+    private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> supportedSpecs) {
         ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
         try {
             StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                     .detectAll()
                     .penaltyDeath()
                     .build());
-            mBindingPkg = callingPackage;
             return onBindSlice(sliceUri, supportedSpecs);
         } finally {
-            mBindingPkg = null;
             StrictMode.setThreadPolicy(oldPolicy);
         }
     }
+
+    private final Runnable mAnr = () -> {
+        Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
+        Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
+    };
 }
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 521ab4e..f7fb84b 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -116,6 +116,14 @@
         @SystemApi
         public static final int STANDBY_BUCKET_CHANGED = 11;
 
+        /**
+         * An event type denoting that an app posted an interruptive notification. Visual and
+         * audible interruptions are included.
+         * @hide
+         */
+        @SystemApi
+        public static final int NOTIFICATION_INTERRUPTION = 12;
+
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
 
@@ -188,6 +196,14 @@
          */
         public int mBucketAndReason;
 
+        /**
+         * The id of the {@link android.app.NotificationChannel} to which an interruptive
+         * notification was posted.
+         * Only present for {@link #NOTIFICATION_INTERRUPTION} event types.
+         * {@hide}
+         */
+        public String mNotificationChannelId;
+
         /** @hide */
         @EventFlags
         public int mFlags;
@@ -208,6 +224,7 @@
             mContentAnnotations = orig.mContentAnnotations;
             mFlags = orig.mFlags;
             mBucketAndReason = orig.mBucketAndReason;
+            mNotificationChannelId = orig.mNotificationChannelId;
         }
 
         /**
@@ -285,6 +302,16 @@
             return mBucketAndReason & 0x0000FFFF;
         }
 
+        /**
+         * Returns the ID of the {@link android.app.NotificationChannel} for this event if the
+         * event is of type {@link #NOTIFICATION_INTERRUPTION}, otherwise it returns null;
+         * @hide
+         */
+        @SystemApi
+        public String getNotificationChannelId() {
+            return mNotificationChannelId;
+        }
+
         /** @hide */
         public Event getObfuscatedIfInstantApp() {
             if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
@@ -444,6 +471,9 @@
             case Event.STANDBY_BUCKET_CHANGED:
                 p.writeInt(event.mBucketAndReason);
                 break;
+            case Event.NOTIFICATION_INTERRUPTION:
+                p.writeString(event.mNotificationChannelId);
+                break;
         }
     }
 
@@ -473,6 +503,7 @@
         eventOut.mAction = null;
         eventOut.mContentType = null;
         eventOut.mContentAnnotations = null;
+        eventOut.mNotificationChannelId = null;
 
         switch (eventOut.mEventType) {
             case Event.CONFIGURATION_CHANGE:
@@ -490,6 +521,9 @@
             case Event.STANDBY_BUCKET_CHANGED:
                 eventOut.mBucketAndReason = p.readInt();
                 break;
+            case Event.NOTIFICATION_INTERRUPTION:
+                eventOut.mNotificationChannelId = p.readString();
+                break;
         }
     }
 
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b62b1ee..09ced26 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -59,6 +59,16 @@
     public abstract void reportConfigurationChange(Configuration config, @UserIdInt int userId);
 
     /**
+     * Reports that an application has posted an interruptive notification.
+     *
+     * @param packageName The package name of the app that posted the notification
+     * @param channelId The ID of the NotificationChannel to which the notification was posted
+     * @param userId The user in which the notification was posted
+     */
+    public abstract void reportInterruptiveNotification(String packageName, String channelId,
+            @UserIdInt int userId);
+
+    /**
      * Reports that an action equivalent to a ShortcutInfo is taken by the user.
      *
      * @param packageName The package name of the shortcut publisher
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
index 1fd9423..1e75bf4 100644
--- a/core/java/android/net/INetdEventCallback.aidl
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -20,8 +20,9 @@
 oneway interface INetdEventCallback {
 
     // Possible addNetdEventCallback callers.
-    const int CALLBACK_CALLER_DEVICE_POLICY = 0;
-    const int CALLBACK_CALLER_NETWORK_WATCHLIST = 1;
+    const int CALLBACK_CALLER_CONNECTIVITY_SERVICE = 0;
+    const int CALLBACK_CALLER_DEVICE_POLICY = 1;
+    const int CALLBACK_CALLER_NETWORK_WATCHLIST = 2;
 
     /**
      * Reports a single DNS lookup function call.
@@ -39,6 +40,18 @@
             int uid);
 
     /**
+     * Represents a private DNS validation success or failure.
+     * This method must not block or perform long-running operations.
+     *
+     * @param netId the ID of the network the validation was performed on.
+     * @param ipAddress the IP address for which validation was performed.
+     * @param hostname the hostname for which validation was performed.
+     * @param validated whether or not validation was successful.
+     */
+    void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname,
+            boolean validated);
+
+    /**
      * Reports a single connect library call.
      * This method must not block or perform long-running operations.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e0a1b3e..29b7931 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11195,6 +11195,20 @@
         public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag";
 
         /**
+         * If 0, turning on dnd manually will last indefinitely.
+         * Else if non-negative, turning on dnd manually will last for this many minutes.
+         * Else (if negative), turning on dnd manually will surface a dialog that prompts
+         * user to specify a duration.
+         * @hide
+         */
+        public static final String ZEN_DURATION = "zen_duration";
+
+        private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR;
+
+        /** @hide */ public static final int ZEN_DURATION_PROMPT = -1;
+        /** @hide */ public static final int ZEN_DURATION_FOREVER = 0;
+
+        /**
          * Defines global heads up toggle.  One of HEADS_UP_OFF, HEADS_UP_ON.
          *
          * @hide
@@ -11575,7 +11589,8 @@
             BLUETOOTH_ON,
             PRIVATE_DNS_MODE,
             PRIVATE_DNS_SPECIFIER,
-            SOFT_AP_TIMEOUT_ENABLED
+            SOFT_AP_TIMEOUT_ENABLED,
+            ZEN_DURATION,
         };
 
         /**
@@ -11616,6 +11631,7 @@
             VALIDATORS.put(WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                     WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
             VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR);
+            VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index c568b6f..140336e 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -49,7 +49,8 @@
  * </ul>
  *
  * <P> The minimum permission needed to access this content provider is
- * {@link android.Manifest.permission#ADD_VOICEMAIL}
+ * {@link android.Manifest.permission#ADD_VOICEMAIL} or carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
  *
  * <P>Voicemails are inserted by what is called as a "voicemail source"
  * application, which is responsible for syncing voicemail data between a remote
diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl
index d2ffe34..25e9d45 100644
--- a/core/java/android/service/textclassifier/ITextClassifierService.aidl
+++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl
@@ -19,13 +19,14 @@
 import android.service.textclassifier.ITextClassificationCallback;
 import android.service.textclassifier.ITextLinksCallback;
 import android.service.textclassifier.ITextSelectionCallback;
+import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextLinks;
 import android.view.textclassifier.TextSelection;
 
 /**
  * TextClassifierService binder interface.
- * See TextClassifier for interface documentation.
+ * See TextClassifier (and TextClassifier.Logger) for interface documentation.
  * {@hide}
  */
 oneway interface ITextClassifierService {
@@ -44,4 +45,6 @@
             in CharSequence text,
             in TextLinks.Options options,
             in ITextLinksCallback c);
+
+    void onSelectionEvent(in SelectionEvent event);
 }
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 57c8def..88e29b0 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.Slog;
+import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
@@ -171,6 +172,12 @@
                         }
                     });
         }
+
+        /** {@inheritDoc} */
+        @Override
+        public void onSelectionEvent(SelectionEvent event) throws RemoteException {
+            TextClassifierService.this.onSelectionEvent(event);
+        }
     };
 
     @Nullable
@@ -238,6 +245,15 @@
             @NonNull Callback<TextLinks> callback);
 
     /**
+     * Writes the selection event.
+     * This is called when a selection event occurs. e.g. user changed selection; or smart selection
+     * happened.
+     *
+     * <p>The default implementation ignores the event.
+     */
+    public void onSelectionEvent(@NonNull SelectionEvent event) {}
+
+    /**
      * Returns a TextClassifier that runs in this service's process.
      * If the local TextClassifier is disabled, this returns {@link TextClassifier#NO_OP}.
      */
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index bb16afd..b6adee9 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -18,10 +18,6 @@
 
 import static android.view.DisplayCutoutProto.BOUNDS;
 import static android.view.DisplayCutoutProto.INSETS;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 
@@ -36,23 +32,24 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.PathParser;
-import android.util.Size;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.util.Objects;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * Represents a part of the display that is not functional for displaying content.
+ * Represents the area of the display that is not functional for displaying content.
  *
  * <p>{@code DisplayCutout} is immutable.
  */
 public final class DisplayCutout {
 
     private static final String TAG = "DisplayCutout";
+    private static final String BOTTOM_MARKER = "@bottom";
     private static final String DP_MARKER = "@dp";
 
     /**
@@ -74,7 +71,7 @@
      * @hide
      */
     public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION,
-            new Size(0, 0));
+            false /* copyArguments */);
 
 
     private static final Object CACHE_LOCK = new Object();
@@ -89,38 +86,38 @@
 
     private final Rect mSafeInsets;
     private final Region mBounds;
-    private final Size mFrameSize;  // TODO: move frameSize, calculateRelativeTo, etc. into WM.
 
     /**
      * Creates a DisplayCutout instance.
      *
      * @param safeInsets the insets from each edge which avoid the display cutout as returned by
      *                   {@link #getSafeInsetTop()} etc.
-     * @param bounds the bounds of the display cutout as returned by {@link #getBounds()}.
+     * @param boundingRects the bounding rects of the display cutouts as returned by
+     *               {@link #getBoundingRects()} ()}.
      */
     // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
-    public DisplayCutout(Rect safeInsets, Region bounds) {
+    public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) {
         this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT,
-                bounds != null ? Region.obtain(bounds) : Region.obtain(),
-                null /* frameSize */);
+                boundingRectsToRegion(boundingRects),
+                true /* copyArguments */);
     }
 
     /**
      * Creates a DisplayCutout instance.
      *
-     * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged.
-     *
-     * @hide
+     * @param copyArguments if true, create a copy of the arguments. If false, the passed arguments
+     *                      are not copied and MUST remain unchanged forever.
      */
-    @VisibleForTesting
-    public DisplayCutout(Rect safeInsets, Region bounds, Size frameSize) {
-        mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT;
-        mBounds = bounds != null ? bounds : Region.obtain();
-        mFrameSize = frameSize;
+    private DisplayCutout(Rect safeInsets, Region bounds, boolean copyArguments) {
+        mSafeInsets = safeInsets == null ? ZERO_RECT :
+                (copyArguments ? new Rect(safeInsets) : safeInsets);
+        mBounds = bounds == null ? Region.obtain() :
+                (copyArguments ? Region.obtain(bounds) : bounds);
     }
 
     /**
-     * Returns true if there is no cutout or it is outside of the content view.
+     * Returns true if the safe insets are empty (and therefore the current view does not
+     * overlap with the cutout or cutout area).
      *
      * @hide
      */
@@ -128,6 +125,15 @@
         return mSafeInsets.equals(ZERO_RECT);
     }
 
+    /**
+     * Returns true if there is no cutout, i.e. the bounds are empty.
+     *
+     * @hide
+     */
+    public boolean isBoundsEmpty() {
+        return mBounds.isEmpty();
+    }
+
     /** Returns the inset from the top which avoids the display cutout in pixels. */
     public int getSafeInsetTop() {
         return mSafeInsets.top;
@@ -161,23 +167,60 @@
     /**
      * Returns the bounding region of the cutout.
      *
+     * <p>
+     * <strong>Note:</strong> There may be more than one cutout, in which case the returned
+     * {@code Region} will be non-contiguous and its bounding rect will be meaningless without
+     * intersecting it first.
+     *
+     * Example:
+     * <pre>
+     *     // Getting the bounding rectangle of the top display cutout
+     *     Region bounds = displayCutout.getBounds();
+     *     bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT);
+     *     Rect topDisplayCutout = bounds.getBoundingRect();
+     * </pre>
+     *
      * @return the bounding region of the cutout. Coordinates are relative
      *         to the top-left corner of the content view and in pixel units.
+     * @hide
      */
     public Region getBounds() {
         return Region.obtain(mBounds);
     }
 
     /**
-     * Returns the bounding rect of the cutout.
+     * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional
+     * area on the display.
      *
-     * @return the bounding rect of the cutout. Coordinates are relative
-     *         to the top-left corner of the content view.
-     * @hide
+     * There will be at most one non-functional area per short edge of the device, and none on
+     * the long edges.
+     *
+     * @return a list of bounding {@code Rect}s, one for each display cutout area.
      */
-    public Rect getBoundingRect() {
-        // TODO(roosa): Inline.
-        return mBounds.getBounds();
+    public List<Rect> getBoundingRects() {
+        List<Rect> result = new ArrayList<>();
+        Region bounds = Region.obtain();
+        // top
+        bounds.set(mBounds);
+        bounds.op(0, 0, Integer.MAX_VALUE, getSafeInsetTop(), Region.Op.INTERSECT);
+        if (!bounds.isEmpty()) {
+            result.add(bounds.getBounds());
+        }
+        // left
+        bounds.set(mBounds);
+        bounds.op(0, 0, getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT);
+        if (!bounds.isEmpty()) {
+            result.add(bounds.getBounds());
+        }
+        // right & bottom
+        bounds.set(mBounds);
+        bounds.op(getSafeInsetLeft() + 1, getSafeInsetTop() + 1,
+                Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT);
+        if (!bounds.isEmpty()) {
+            result.add(bounds.getBounds());
+        }
+        bounds.recycle();
+        return result;
     }
 
     @Override
@@ -195,8 +238,7 @@
         if (o instanceof DisplayCutout) {
             DisplayCutout c = (DisplayCutout) o;
             return mSafeInsets.equals(c.mSafeInsets)
-                    && mBounds.equals(c.mBounds)
-                    && Objects.equals(mFrameSize, c.mFrameSize);
+                    && mBounds.equals(c.mBounds);
         }
         return false;
     }
@@ -204,7 +246,7 @@
     @Override
     public String toString() {
         return "DisplayCutout{insets=" + mSafeInsets
-                + " boundingRect=" + getBoundingRect()
+                + " boundingRect=" + mBounds.getBounds()
                 + "}";
     }
 
@@ -249,88 +291,19 @@
         }
 
         bounds.translate(-insetLeft, -insetTop);
-        Size frame = mFrameSize == null ? null : new Size(
-                mFrameSize.getWidth() - insetLeft - insetRight,
-                mFrameSize.getHeight() - insetTop - insetBottom);
-
-        return new DisplayCutout(safeInsets, bounds, frame);
+        return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
     }
 
     /**
-     * Recalculates the cutout relative to the given reference frame.
+     * Returns a copy of this instance with the safe insets replaced with the parameter.
      *
-     * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}.
+     * @param safeInsets the new safe insets in pixels
+     * @return a copy of this instance with the safe insets replaced with the argument.
      *
-     * @return a copy of this instance with the safe insets recalculated
      * @hide
      */
-    public DisplayCutout calculateRelativeTo(Rect frame) {
-        return inset(frame.left, frame.top,
-                mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom);
-    }
-
-    /**
-     * Calculates the safe insets relative to the given display size.
-     *
-     * @return a copy of this instance with the safe insets calculated
-     * @hide
-     */
-    public DisplayCutout computeSafeInsets(int width, int height) {
-        if (this == NO_CUTOUT || mBounds.isEmpty()) {
-            return NO_CUTOUT;
-        }
-
-        return computeSafeInsets(new Size(width, height), mBounds);
-    }
-
-    private static DisplayCutout computeSafeInsets(Size displaySize, Region bounds) {
-        Rect boundingRect = bounds.getBounds();
-        Rect safeRect = new Rect();
-
-        int bestArea = 0;
-        int bestVariant = 0;
-        for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) {
-            int area = calculateInsetVariantArea(displaySize, boundingRect, variant, safeRect);
-            if (bestArea < area) {
-                bestArea = area;
-                bestVariant = variant;
-            }
-        }
-        calculateInsetVariantArea(displaySize, boundingRect, bestVariant, safeRect);
-        if (safeRect.isEmpty()) {
-            // The entire displaySize overlaps with the cutout.
-            safeRect.set(0, displaySize.getHeight(), 0, 0);
-        } else {
-            // Convert safeRect to insets relative to displaySize. We're reusing the rect here to
-            // avoid an allocation.
-            safeRect.set(
-                    Math.max(0, safeRect.left),
-                    Math.max(0, safeRect.top),
-                    Math.max(0, displaySize.getWidth() - safeRect.right),
-                    Math.max(0, displaySize.getHeight() - safeRect.bottom));
-        }
-
-        return new DisplayCutout(safeRect, bounds, displaySize);
-    }
-
-    private static int calculateInsetVariantArea(Size display, Rect boundingRect, int variant,
-            Rect outSafeRect) {
-        switch (variant) {
-            case ROTATION_0:
-                outSafeRect.set(0, 0, display.getWidth(), boundingRect.top);
-                break;
-            case ROTATION_90:
-                outSafeRect.set(0, 0, boundingRect.left, display.getHeight());
-                break;
-            case ROTATION_180:
-                outSafeRect.set(0, boundingRect.bottom, display.getWidth(), display.getHeight());
-                break;
-            case ROTATION_270:
-                outSafeRect.set(boundingRect.right, 0, display.getWidth(), display.getHeight());
-                break;
-        }
-
-        return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height();
+    public DisplayCutout replaceSafeInsets(Rect safeInsets) {
+        return new DisplayCutout(new Rect(safeInsets), mBounds, false /* copyArguments */);
     }
 
     private static int atLeastZero(int value) {
@@ -369,7 +342,7 @@
         Region bounds = new Region();
         bounds.setPath(path, clipRegion);
         clipRegion.recycle();
-        return new DisplayCutout(ZERO_RECT, bounds, null /* frameSize */);
+        return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
     }
 
     /**
@@ -377,9 +350,9 @@
      *
      * @hide
      */
-    public static DisplayCutout fromResources(Resources res, int displayWidth) {
+    public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) {
         return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
-                displayWidth, res.getDisplayMetrics().density);
+                displayWidth, displayHeight, res.getDisplayMetrics().density);
     }
 
     /**
@@ -388,7 +361,8 @@
      * @hide
      */
     @VisibleForTesting(visibility = PRIVATE)
-    public static DisplayCutout fromSpec(String spec, int displayWidth, float density) {
+    public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
+            float density) {
         if (TextUtils.isEmpty(spec)) {
             return null;
         }
@@ -404,7 +378,14 @@
             spec = spec.substring(0, spec.length() - DP_MARKER.length());
         }
 
-        Path p;
+        String bottomSpec = null;
+        if (spec.contains(BOTTOM_MARKER)) {
+            String[] splits = spec.split(BOTTOM_MARKER, 2);
+            spec = splits[0].trim();
+            bottomSpec = splits[1].trim();
+        }
+
+        final Path p;
         try {
             p = PathParser.createPathFromPathData(spec);
         } catch (Throwable e) {
@@ -419,6 +400,20 @@
         m.postTranslate(displayWidth / 2f, 0);
         p.transform(m);
 
+        if (bottomSpec != null) {
+            final Path bottomPath;
+            try {
+                bottomPath = PathParser.createPathFromPathData(bottomSpec);
+            } catch (Throwable e) {
+                Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
+                return null;
+            }
+            // Keep top transform
+            m.postTranslate(0, displayHeight);
+            bottomPath.transform(m);
+            p.addPath(bottomPath);
+        }
+
         final DisplayCutout result = fromBounds(p);
         synchronized (CACHE_LOCK) {
             sCachedSpec = spec;
@@ -429,6 +424,16 @@
         return result;
     }
 
+    private static Region boundingRectsToRegion(List<Rect> rects) {
+        Region result = Region.obtain();
+        if (rects != null) {
+            for (Rect r : rects) {
+                result.op(r, Region.Op.UNION);
+            }
+        }
+        return result;
+    }
+
     /**
      * Helper class for passing {@link DisplayCutout} through binder.
      *
@@ -472,12 +477,6 @@
                 out.writeInt(1);
                 out.writeTypedObject(cutout.mSafeInsets, flags);
                 out.writeTypedObject(cutout.mBounds, flags);
-                if (cutout.mFrameSize != null) {
-                    out.writeInt(cutout.mFrameSize.getWidth());
-                    out.writeInt(cutout.mFrameSize.getHeight());
-                } else {
-                    out.writeInt(-1);
-                }
             }
         }
 
@@ -520,10 +519,7 @@
             Rect safeInsets = in.readTypedObject(Rect.CREATOR);
             Region bounds = in.readTypedObject(Region.CREATOR);
 
-            int width = in.readInt();
-            Size frameSize = width >= 0 ? new Size(width, in.readInt()) : null;
-
-            return new DisplayCutout(safeInsets, bounds, frameSize);
+            return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
         }
 
         public DisplayCutout get() {
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 75cdd49..5b2cc81 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -16,13 +16,26 @@
 
 package android.view;
 
+import static android.app.RemoteAnimationTargetProto.CLIP_RECT;
+import static android.app.RemoteAnimationTargetProto.CONTENT_INSETS;
+import static android.app.RemoteAnimationTargetProto.IS_TRANSLUCENT;
+import static android.app.RemoteAnimationTargetProto.LEASH;
+import static android.app.RemoteAnimationTargetProto.MODE;
+import static android.app.RemoteAnimationTargetProto.POSITION;
+import static android.app.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
+import static android.app.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
+import static android.app.RemoteAnimationTargetProto.TASK_ID;
+import static android.app.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
+
 import android.annotation.IntDef;
 import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -164,6 +177,35 @@
         dest.writeBoolean(isNotInRecents);
     }
 
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mode="); pw.print(mode);
+        pw.print(" taskId="); pw.print(taskId);
+        pw.print(" isTranslucent="); pw.print(isTranslucent);
+        pw.print(" clipRect="); clipRect.printShortString(pw);
+        pw.print(" contentInsets="); contentInsets.printShortString(pw);
+        pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
+        pw.print(" position="); position.printShortString(pw);
+        pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
+        pw.println();
+        pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
+        pw.print(prefix); pw.print("leash="); pw.println(leash);
+    }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(TASK_ID, taskId);
+        proto.write(MODE, mode);
+        leash.writeToProto(proto, LEASH);
+        proto.write(IS_TRANSLUCENT, isTranslucent);
+        clipRect.writeToProto(proto, CLIP_RECT);
+        contentInsets.writeToProto(proto, CONTENT_INSETS);
+        proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
+        position.writeToProto(proto, POSITION);
+        sourceContainerBounds.writeToProto(proto, SOURCE_CONTAINER_BOUNDS);
+        windowConfiguration.writeToProto(proto, WINDOW_CONFIGURATION);
+        proto.end(token);
+    }
+
     public static final Creator<RemoteAnimationTarget> CREATOR
             = new Creator<RemoteAnimationTarget>() {
         public RemoteAnimationTarget createFromParcel(Parcel in) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2354f25..69938cb 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2241,18 +2241,20 @@
 
         /**
          * The window is allowed to extend into the {@link DisplayCutout} area, only if the
-         * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+         * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is
          * laid out such that it does not overlap with the {@link DisplayCutout} area.
          *
          * <p>
          * In practice, this means that if the window did not set FLAG_FULLSCREEN or
-         * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait.
-         * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the
+         * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout
+         * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the
+         * bottom of the screen.
+         * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the
          * cutout area.
          *
          * <p>
-         * The usual precautions for not overlapping with the status bar are sufficient for ensuring
-         * that no important content overlaps with the DisplayCutout.
+         * The usual precautions for not overlapping with the status and navigation bar are
+         * sufficient for ensuring that no important content overlaps with the DisplayCutout.
          *
          * @see DisplayCutout
          * @see WindowInsets
@@ -2260,8 +2262,18 @@
         public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
 
         /**
-         * The window is always allowed to extend into the {@link DisplayCutout} area,
-         * even if fullscreen or in landscape.
+         * @deprecated use {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES}
+         * @hide
+         */
+        @Deprecated
+        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
+
+        /**
+         * The window is always allowed to extend into the {@link DisplayCutout} areas on the short
+         * edges of the screen.
+         *
+         * The window will never extend into a {@link DisplayCutout} area on the long edges of the
+         * screen.
          *
          * <p>
          * The window must make sure that no important content overlaps with the
@@ -2270,7 +2282,7 @@
          * @see DisplayCutout
          * @see WindowInsets#getDisplayCutout()
          */
-        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
+        public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;
 
         /**
          * The window is never allowed to overlap with the DisplayCutout area.
diff --git a/core/java/android/view/textclassifier/Logger.java b/core/java/android/view/textclassifier/Logger.java
index a4f5bf1..9c92fd4 100644
--- a/core/java/android/view/textclassifier/Logger.java
+++ b/core/java/android/view/textclassifier/Logger.java
@@ -94,10 +94,7 @@
     }
 
     /**
-     * Writes the selection event.
-     *
-     * <p><strong>NOTE: </strong>This method is designed for subclasses.
-     * Apps should not call it directly.
+     * Writes the selection event to a log.
      */
     public abstract void writeEvent(@NonNull SelectionEvent event);
 
diff --git a/core/java/android/view/textclassifier/SelectionEvent.aidl b/core/java/android/view/textclassifier/SelectionEvent.aidl
new file mode 100644
index 0000000..10ed16e
--- /dev/null
+++ b/core/java/android/view/textclassifier/SelectionEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+package android.view.textclassifier;
+
+parcelable SelectionEvent;
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 90fd921..7ac094e 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -18,6 +18,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.view.textclassifier.TextClassifier.EntityType;
 
 import com.android.internal.util.Preconditions;
@@ -25,12 +27,13 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * A selection event.
  * Specify index parameters as word token indices.
  */
-public final class SelectionEvent {
+public final class SelectionEvent implements Parcelable {
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -121,9 +124,9 @@
     private String mSignature;
     private long mEventTime;
     private long mDurationSinceSessionStart;
-    private long mDurationSinceLastEvent;
+    private long mDurationSincePreviousEvent;
     private int mEventIndex;
-    private String mSessionId;
+    @Nullable private String mSessionId;
     private int mStart;
     private int mEnd;
     private int mSmartStart;
@@ -146,6 +149,60 @@
         mInvocationMethod = invocationMethod;
     }
 
+    private SelectionEvent(Parcel in) {
+        mAbsoluteStart = in.readInt();
+        mAbsoluteEnd = in.readInt();
+        mEventType = in.readInt();
+        mEntityType = in.readString();
+        mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
+        mPackageName = in.readString();
+        mWidgetType = in.readString();
+        mInvocationMethod = in.readInt();
+        mSignature = in.readString();
+        mEventTime = in.readLong();
+        mDurationSinceSessionStart = in.readLong();
+        mDurationSincePreviousEvent = in.readLong();
+        mEventIndex = in.readInt();
+        mSessionId = in.readInt() > 0 ? in.readString() : null;
+        mStart = in.readInt();
+        mEnd = in.readInt();
+        mSmartStart = in.readInt();
+        mSmartEnd = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mAbsoluteStart);
+        dest.writeInt(mAbsoluteEnd);
+        dest.writeInt(mEventType);
+        dest.writeString(mEntityType);
+        dest.writeInt(mWidgetVersion != null ? 1 : 0);
+        if (mWidgetVersion != null) {
+            dest.writeString(mWidgetVersion);
+        }
+        dest.writeString(mPackageName);
+        dest.writeString(mWidgetType);
+        dest.writeInt(mInvocationMethod);
+        dest.writeString(mSignature);
+        dest.writeLong(mEventTime);
+        dest.writeLong(mDurationSinceSessionStart);
+        dest.writeLong(mDurationSincePreviousEvent);
+        dest.writeInt(mEventIndex);
+        dest.writeInt(mSessionId != null ? 1 : 0);
+        if (mSessionId != null) {
+            dest.writeString(mSessionId);
+        }
+        dest.writeInt(mStart);
+        dest.writeInt(mEnd);
+        dest.writeInt(mSmartStart);
+        dest.writeInt(mSmartEnd);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
     int getAbsoluteStart() {
         return mAbsoluteStart;
     }
@@ -240,11 +297,11 @@
      * in the selection session was triggered.
      */
     public long getDurationSincePreviousEvent() {
-        return mDurationSinceLastEvent;
+        return mDurationSincePreviousEvent;
     }
 
     SelectionEvent setDurationSincePreviousEvent(long durationMs) {
-        this.mDurationSinceLastEvent = durationMs;
+        this.mDurationSincePreviousEvent = durationMs;
         return this;
     }
 
@@ -342,15 +399,66 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
+                mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mSignature,
+                mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
+                mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SelectionEvent)) {
+            return false;
+        }
+
+        final SelectionEvent other = (SelectionEvent) obj;
+        return mAbsoluteStart == other.mAbsoluteStart
+                && mAbsoluteEnd == other.mAbsoluteEnd
+                && mEventType == other.mEventType
+                && Objects.equals(mEntityType, other.mEntityType)
+                && Objects.equals(mWidgetVersion, other.mWidgetVersion)
+                && Objects.equals(mPackageName, other.mPackageName)
+                && Objects.equals(mWidgetType, other.mWidgetType)
+                && mInvocationMethod == other.mInvocationMethod
+                && Objects.equals(mSignature, other.mSignature)
+                && mEventTime == other.mEventTime
+                && mDurationSinceSessionStart == other.mDurationSinceSessionStart
+                && mDurationSincePreviousEvent == other.mDurationSincePreviousEvent
+                && mEventIndex == other.mEventIndex
+                && Objects.equals(mSessionId, other.mSessionId)
+                && mStart == other.mStart
+                && mEnd == other.mEnd
+                && mSmartStart == other.mSmartStart
+                && mSmartEnd == other.mSmartEnd;
+    }
+
+    @Override
     public String toString() {
         return String.format(Locale.US,
         "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, "
-                + "widgetVersion=%s, packageName=%s, widgetType=%s, signature=%s, "
-                + "eventTime=%d, durationSinceSessionStart=%d, durationSinceLastEvent=%d, "
-                + "eventIndex=%d, sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d}",
+                + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, "
+                + "signature=%s, eventTime=%d, durationSinceSessionStart=%d, "
+                + "durationSincePreviousEvent=%d, eventIndex=%d, sessionId=%s, start=%d, end=%d, "
+                + "smartStart=%d, smartEnd=%d}",
                 mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
-                mWidgetVersion, mPackageName, mWidgetType, mSignature,
-                mEventTime, mDurationSinceSessionStart, mDurationSinceLastEvent,
+                mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mSignature,
+                mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
                 mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
     }
+
+    public static final Creator<SelectionEvent> CREATOR = new Creator<SelectionEvent>() {
+        @Override
+        public SelectionEvent createFromParcel(Parcel in) {
+            return new SelectionEvent(in);
+        }
+
+        @Override
+        public SelectionEvent[] newArray(int size) {
+            return new SelectionEvent[size];
+        }
+    };
 }
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 2b335fb..c783cae 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -29,6 +29,7 @@
 import android.service.textclassifier.ITextLinksCallback;
 import android.service.textclassifier.ITextSelectionCallback;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
 import java.util.concurrent.CountDownLatch;
@@ -46,6 +47,12 @@
     private final TextClassifier mFallback;
     private final String mPackageName;
 
+    private final Object mLoggerLock = new Object();
+    @GuardedBy("mLoggerLock")
+    private Logger.Config mLoggerConfig;
+    @GuardedBy("mLoggerLock")
+    private Logger mLogger;
+
     SystemTextClassifier(Context context, TextClassificationConstants settings)
                 throws ServiceManager.ServiceNotFoundException {
         mManagerService = ITextClassifierService.Stub.asInterface(
@@ -58,6 +65,7 @@
     /**
      * @inheritDoc
      */
+    @Override
     @WorkerThread
     public TextSelection suggestSelection(
             @NonNull CharSequence text,
@@ -84,6 +92,7 @@
     /**
      * @inheritDoc
      */
+    @Override
     @WorkerThread
     public TextClassification classifyText(
             @NonNull CharSequence text,
@@ -109,6 +118,7 @@
     /**
      * @inheritDoc
      */
+    @Override
     @WorkerThread
     public TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
@@ -142,11 +152,33 @@
      * @inheritDoc
      */
     @Override
+    @WorkerThread
     public int getMaxGenerateLinksTextLength() {
         // TODO: retrieve this from the bound service.
         return mFallback.getMaxGenerateLinksTextLength();
     }
 
+    @Override
+    public Logger getLogger(@NonNull Logger.Config config) {
+        Preconditions.checkNotNull(config);
+        synchronized (mLoggerLock) {
+            if (mLogger == null || !config.equals(mLoggerConfig)) {
+                mLoggerConfig = config;
+                mLogger = new Logger(config) {
+                    @Override
+                    public void writeEvent(SelectionEvent event) {
+                        try {
+                            mManagerService.onSelectionEvent(event);
+                        } catch (RemoteException e) {
+                            e.rethrowAsRuntimeException();
+                        }
+                    }
+                };
+            }
+        }
+        return mLogger;
+    }
+
     private static final class TextSelectionCallback extends ITextSelectionCallback.Stub {
 
         final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>();
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ebd2ff9..887bebb 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -323,6 +323,7 @@
      * @see #generateLinks(CharSequence)
      * @see #generateLinks(CharSequence, TextLinks.Options)
      */
+    @WorkerThread
     default int getMaxGenerateLinksTextLength() {
         return Integer.MAX_VALUE;
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 0a05269..a099820 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.ContentUris;
@@ -42,7 +43,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.lang.ref.WeakReference;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -78,7 +78,6 @@
 
     private final Context mContext;
     private final TextClassifier mFallback;
-
     private final GenerateLinksLogger mGenerateLinksLogger;
 
     private final Object mLock = new Object();
@@ -91,9 +90,9 @@
 
     private final Object mLoggerLock = new Object();
     @GuardedBy("mLoggerLock") // Do not access outside this lock.
-    private WeakReference<Logger.Config> mLoggerConfig = new WeakReference<>(null);
+    private Logger.Config mLoggerConfig;
     @GuardedBy("mLoggerLock") // Do not access outside this lock.
-    private Logger mLogger;  // Should never be null if mLoggerConfig.get() is not null.
+    private Logger mLogger;
 
     private final TextClassificationConstants mSettings;
 
@@ -106,6 +105,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextSelection suggestSelection(
             @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
             @Nullable TextSelection.Options options) {
@@ -169,6 +169,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextClassification classifyText(
             @NonNull CharSequence text, int startIndex, int endIndex,
             @Nullable TextClassification.Options options) {
@@ -204,6 +205,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
         Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
@@ -282,16 +284,17 @@
         }
     }
 
+    /** @inheritDoc */
     @Override
     public Logger getLogger(@NonNull Logger.Config config) {
         Preconditions.checkNotNull(config);
         synchronized (mLoggerLock) {
-            if (mLoggerConfig.get() == null || !mLoggerConfig.get().equals(config)) {
-                mLoggerConfig = new WeakReference<>(config);
+            if (mLogger == null || !config.equals(mLoggerConfig)) {
+                mLoggerConfig = config;
                 mLogger = new DefaultLogger(config);
             }
-            return mLogger;
         }
+        return mLogger;
     }
 
     private TextClassifierImplNative getNative(LocaleList localeList)
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5d3f1c9..f39b73e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2906,6 +2906,11 @@
         mProvider.getViewDelegate().autofill(values);
     }
 
+    @Override
+    public boolean isVisibleToUserForAutofill(int virtualId) {
+        return mProvider.getViewDelegate().isVisibleToUserForAutofill(virtualId);
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index a474a85..00e782b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -329,13 +329,16 @@
 
         public void onProvideVirtualStructure(android.view.ViewStructure structure);
 
-        @SuppressWarnings("unused")
-        public default void onProvideAutofillVirtualStructure(android.view.ViewStructure structure,
-                int flags) {
+        default void onProvideAutofillVirtualStructure(
+                @SuppressWarnings("unused") android.view.ViewStructure structure,
+                @SuppressWarnings("unused") int flags) {
         }
 
-        @SuppressWarnings("unused")
-        public default void autofill(SparseArray<AutofillValue>values) {
+        default void autofill(@SuppressWarnings("unused") SparseArray<AutofillValue> values) {
+        }
+
+        default boolean isVisibleToUserForAutofill(@SuppressWarnings("unused") int virtualId) {
+            return true; // true is the default value returned by View.isVisibleToUserForAutofill()
         }
 
         public AccessibilityNodeProvider getAccessibilityNodeProvider();
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 629f531..be8c34c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -648,6 +648,9 @@
      * Part selection of a word e.g. "or" is counted as selecting the
      * entire word i.e. equivalent to "York", and each special character is counted as a word, e.g.
      * "," is at [2, 3). Whitespaces are ignored.
+     *
+     * NOTE that the definition of a word is defined by the TextClassifier's Logger's token
+     * iterator.
      */
     private static final class SelectionMetricsLogger {
 
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 9d4b5aa..c71e505 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -22,6 +22,7 @@
 import android.content.ComponentName;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Process;
 import android.os.storage.StorageManager;
@@ -276,9 +277,12 @@
         readPermissions(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
 
-        // Allow Vendor to customize system configs around libs, features, permissions and apps
-        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
-                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+        // Vendors are only allowed to customze libs, features and privapp permissions
+        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
+        if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
+            // For backward compatibility
+            vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
+        }
         readPermissions(Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
         readPermissions(Environment.buildPath(
@@ -659,6 +663,8 @@
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else {
+                    Slog.w(TAG, "Tag " + name + " is unknown or not allowed in "
+                            + permFile.getParent());
                     XmlUtils.skipCurrentTag(parser);
                     continue;
                 }
diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java
index 3d3a3d0..fdba2f3 100644
--- a/core/java/com/android/server/net/BaseNetdEventCallback.java
+++ b/core/java/com/android/server/net/BaseNetdEventCallback.java
@@ -32,6 +32,12 @@
     }
 
     @Override
+    public void onPrivateDnsValidationEvent(int netId, String ipAddress,
+            String hostname, boolean validated) {
+        // default no-op
+    }
+
+    @Override
     public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
         // default no-op
     }
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 5498a93..ce4e384 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -921,6 +921,28 @@
 
     SkBitmap skbitmap;
     bitmap->getSkBitmap(&skbitmap);
+    if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
+        // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
+        // for wide gamuts.
+        auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
+                                        SkColorSpace::kDCIP3_D65_Gamut);
+        auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
+                                   .makeColorSpace(std::move(cs));
+        SkBitmap p3;
+        if (!p3.tryAllocPixels(info)) {
+            return JNI_FALSE;
+        }
+        auto xform = SkColorSpaceXform::New(skbitmap.colorSpace(), info.colorSpace());
+        if (!xform) {
+            return JNI_FALSE;
+        }
+        if (!xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, p3.getPixels(),
+                          SkColorSpaceXform::kRGBA_F16_ColorFormat, skbitmap.getPixels(),
+                          info.width() * info.height(), kUnpremul_SkAlphaType)) {
+            return JNI_FALSE;
+        }
+        skbitmap = p3;
+    }
     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index d7ba421..914a7db 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -433,9 +433,11 @@
     optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingsProto show_zen_upgrade_notification = 354  [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingsProto app_auto_restriction_enabled = 359  [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingsProto zen_duration = 360  [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     // Please insert fields in the same order as in
     // frameworks/base/core/java/android/provider/Settings.java.
-    // Next tag = 360;
+    // Next tag = 361;
 }
 
 message SecureSettingsProto {
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
new file mode 100644
index 0000000..c4ffe8c
--- /dev/null
+++ b/core/proto/android/server/animationadapter.proto
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/graphics/point.proto";
+import "frameworks/base/core/proto/android/view/remote_animation_target.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+package com.android.server.wm.proto;
+option java_multiple_files = true;
+
+message AnimationAdapterProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional LocalAnimationAdapterProto local = 1;
+  optional RemoteAnimationAdapterWrapperProto remote = 2;
+}
+
+/* represents RemoteAnimationAdapterWrapper */
+message RemoteAnimationAdapterWrapperProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional .android.view.RemoteAnimationTargetProto target = 1;
+}
+
+/* represents LocalAnimationAdapter */
+message LocalAnimationAdapterProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional AnimationSpecProto animation_spec = 1;
+}
+
+message AnimationSpecProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional WindowAnimationSpecProto window = 1;
+  optional MoveAnimationSpecProto move = 2;
+  optional AlphaAnimationSpecProto alpha = 3;
+}
+
+/* represents WindowAnimationSpec */
+message WindowAnimationSpecProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional string animation = 1;
+}
+
+/* represents MoveAnimationSpec*/
+message MoveAnimationSpecProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional .android.graphics.PointProto from = 1;
+  optional .android.graphics.PointProto to = 2;
+  optional int64 duration = 3;
+}
+
+/* represents AlphaAnimationSpec */
+message AlphaAnimationSpecProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional float from = 1;
+  optional float to = 2;
+  optional int64 duration = 3;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto
index 7f7839e..dcc2b34 100644
--- a/core/proto/android/server/surfaceanimator.proto
+++ b/core/proto/android/server/surfaceanimator.proto
@@ -16,6 +16,7 @@
 
 syntax = "proto2";
 
+import "frameworks/base/core/proto/android/server/animationadapter.proto";
 import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
@@ -28,7 +29,8 @@
 message SurfaceAnimatorProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional string animation_adapter = 1;
+  reserved 1; // Was string animation_adapter = 1
   optional .android.view.SurfaceControlProto leash = 2;
   optional bool animation_start_delayed = 3;
+  optional AnimationAdapterProto animation_adapter = 4;
 }
\ No newline at end of file
diff --git a/core/proto/android/view/remote_animation_target.proto b/core/proto/android/view/remote_animation_target.proto
new file mode 100644
index 0000000..d5da0a9
--- /dev/null
+++ b/core/proto/android/view/remote_animation_target.proto
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.view;
+
+import "frameworks/base/core/proto/android/app/window_configuration.proto";
+import "frameworks/base/core/proto/android/graphics/point.proto";
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+/** Proto representation for RemoteAnimationTarget.java class. */
+message RemoteAnimationTargetProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional int32 task_id = 1;
+  optional int32 mode = 2;
+  optional .android.view.SurfaceControlProto leash = 3;
+  optional bool is_translucent = 4;
+  optional .android.graphics.RectProto clip_rect = 5;
+  optional .android.graphics.RectProto contentInsets = 6;
+  optional int32 prefix_order_index = 7;
+  optional .android.graphics.PointProto position = 8;
+  optional .android.graphics.RectProto source_container_bounds = 9;
+  optional .android.app.WindowConfigurationProto window_configuration = 10;
+}
diff --git a/core/res/res/drawable/ic_corp_user_badge.xml b/core/res/res/drawable/ic_corp_user_badge.xml
index 6a0d902..a08f2d4 100644
--- a/core/res/res/drawable/ic_corp_user_badge.xml
+++ b/core/res/res/drawable/ic_corp_user_badge.xml
@@ -2,7 +2,8 @@
         android:width="36dp"
         android:height="36dp"
         android:viewportWidth="36.0"
-        android:viewportHeight="36.0">
+        android:viewportHeight="36.0"
+        android:tint="?attr/colorControlNormal">
     <path
         android:pathData="M16.3,11.3h3.4v1.7h-3.4z"
         android:fillColor="#FFFFFF"/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6d23fab..4a72bf9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2125,29 +2125,32 @@
         Defaults to {@code default}.
 
         @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
-        @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+        @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
         @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
         @see android.view.DisplayCutout
         @see android.R.attr#layoutInDisplayCutoutMode -->
         <attr name="windowLayoutInDisplayCutoutMode">
             <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the
-            {@code DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+            {@code DisplayCutout} is fully contained within a system bar. Otherwise, the window is
             laid out such that it does not overlap with the {@code DisplayCutout} area.
 
             @see android.view.DisplayCutout
             @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
             -->
             <enum name="default" value="0" />
-            <!-- The window is always allowed to extend into the {@code DisplayCutout} area,
-            even if fullscreen or in landscape.
+            <!--
+            The window is always allowed to extend into the {@code DisplayCutout} areas on the short
+            edges of the screen even if fullscreen or in landscape.
+            The window will never extend into a {@link DisplayCutout} area on the long edges of the
+            screen.
             <p>
             The window must make sure that no important content overlaps with the
             {@link DisplayCutout}.
 
             @see android.view.DisplayCutout
-            @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+            @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
             -->
-            <enum name="always" value="1" />
+            <enum name="shortEdges" value="1" />
             <!-- The window is never allowed to overlap with the DisplayCutout area.
             <p>
             This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a5bd179..dc937e6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4490,7 +4490,7 @@
 
     <!-- Zen mode condition - summary: time duration in hours. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_hours_summary">
-        <item quantity="one">For one hour (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
+        <item quantity="one">For 1 hour (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
         <item quantity="other">For %1$d hours (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
     </plurals>
 
@@ -4514,7 +4514,7 @@
 
     <!-- Zen mode condition - line one: time duration in hours. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_hours">
-        <item quantity="one">For one hour</item>
+        <item quantity="one">For 1 hour</item>
         <item quantity="other">For %d hours</item>
     </plurals>
 
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index fdbcd8a..25b053b 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1318,6 +1318,9 @@
         <!-- Progress bar attributes -->
         <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
         <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+        <!-- volume background -->
+        <item name="panelColorBackground">@color/primary_material_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 53c22f6..0f019e71 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1379,6 +1379,10 @@
             android:theme="@style/Theme">
         </activity>
 
+        <activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
+            android:exported="true">
+        </activity>
+
         <activity
             android:name="android.os.TestVrActivity"
             android:enableVrMode="com.android.frameworks.coretests/android.os.TestVrActivity$TestVrListenerService">
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index ef3a481..bcde4c1 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -25,8 +25,8 @@
     <style name="LayoutInDisplayCutoutModeDefault">
         <item name="android:windowLayoutInDisplayCutoutMode">default</item>
     </style>
-    <style name="LayoutInDisplayCutoutModeAlways">
-        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
+    <style name="LayoutInDisplayCutoutModeShortEdges">
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
     </style>
     <style name="LayoutInDisplayCutoutModeNever">
         <item name="android:windowLayoutInDisplayCutoutMode">never</item>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
new file mode 100644
index 0000000..4628aa9
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.app.activity;
+
+import android.app.Activity;
+import android.app.IApplicationThread;
+import android.app.servertransaction.ActivityRelaunchItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.MergedConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for verifying {@link android.app.ActivityThread} class.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class ActivityThreadTest {
+
+    private final ActivityTestRule mActivityTestRule =
+            new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
+                    false /* launchActivity */);
+
+    @Test
+    public void testDoubleRelaunch() throws Exception {
+        final Activity activity = mActivityTestRule.launchActivity(new Intent());
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+
+        appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+        appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testResumeAfterRelaunch() throws Exception {
+        final Activity activity = mActivityTestRule.launchActivity(new Intent());
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+
+        appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+        appThread.scheduleTransaction(newResumeTransaction(activity));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
+        final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
+                null, 0, new MergedConfiguration(),
+                false /* preserveWindow */);
+        final ResumeActivityItem resumeStateRequest =
+                ResumeActivityItem.obtain(true /* isForward */);
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+        final ClientTransaction transaction =
+                ClientTransaction.obtain(appThread, activity.getActivityToken());
+        transaction.addCallback(callbackItem);
+        transaction.setLifecycleStateRequest(resumeStateRequest);
+
+        return transaction;
+    }
+
+    private static ClientTransaction newResumeTransaction(Activity activity) {
+        final ResumeActivityItem resumeStateRequest =
+                ResumeActivityItem.obtain(true /* isForward */);
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+        final ClientTransaction transaction =
+                ClientTransaction.obtain(appThread, activity.getActivityToken());
+        transaction.setLifecycleStateRequest(resumeStateRequest);
+
+        return transaction;
+    }
+
+    // Test activity
+    public static class TestActivity extends Activity {
+    }
+}
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index d807353..6e9401d 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -17,7 +17,6 @@
 package android.view;
 
 import static android.view.DisplayCutout.NO_CUTOUT;
-import static android.view.DisplayCutout.fromBoundingRect;
 import static android.view.DisplayCutout.fromSpec;
 
 import static org.hamcrest.Matchers.not;
@@ -29,17 +28,17 @@
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.Size;
 import android.view.DisplayCutout.ParcelableWrapper;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
@@ -48,7 +47,7 @@
     /** This is not a consistent cutout. Useful for verifying insets in one go though. */
     final DisplayCutout mCutoutNumbers = new DisplayCutout(
             new Rect(1, 2, 3, 4),
-            new Region(5, 6, 7, 8), new Size(9, 10));
+            Arrays.asList(new Rect(5, 6, 7, 8)));
 
     final DisplayCutout mCutoutTop = createCutoutTop();
 
@@ -70,7 +69,7 @@
 
     @Test
     public void getBoundingRect() throws Exception {
-        assertEquals(new Rect(50, 0, 75, 100), mCutoutTop.getBoundingRect());
+        assertEquals(new Rect(50, 0, 75, 100), mCutoutTop.getBounds().getBounds());
     }
 
     @Test
@@ -154,91 +153,7 @@
     public void inset_bounds() throws Exception {
         DisplayCutout cutout = mCutoutTop.inset(1, 2, 3, 4);
 
-        assertEquals(new Rect(49, -2, 74, 98), cutout.getBoundingRect());
-    }
-
-    @Test
-    public void computeSafeInsets_top() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 0, 100, 20)
-                .computeSafeInsets(200, 400);
-
-        assertEquals(new Rect(0, 20, 0, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void computeSafeInsets_left() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 0, 20, 100)
-                .computeSafeInsets(400, 200);
-
-        assertEquals(new Rect(20, 0, 0, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void computeSafeInsets_bottom() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 180, 100, 200)
-                .computeSafeInsets(100, 200);
-
-        assertEquals(new Rect(0, 0, 0, 20), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void computeSafeInsets_right() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(180, 0, 200, 100)
-                .computeSafeInsets(200, 100);
-
-        assertEquals(new Rect(0, 0, 20, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void computeSafeInsets_bounds() throws Exception {
-        DisplayCutout cutout = mCutoutTop.computeSafeInsets(1000, 2000);
-
-        assertEquals(mCutoutTop.getBoundingRect(), cutout.getBounds().getBounds());
-    }
-
-    @Test
-    public void calculateRelativeTo_top() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 0, 100, 20)
-                .computeSafeInsets(200, 400)
-                .calculateRelativeTo(new Rect(5, 5, 95, 195));
-
-        assertEquals(new Rect(0, 15, 0, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void calculateRelativeTo_left() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 0, 20, 100)
-                .computeSafeInsets(400, 200)
-                .calculateRelativeTo(new Rect(5, 5, 195, 95));
-
-        assertEquals(new Rect(15, 0, 0, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void calculateRelativeTo_bottom() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 180, 100, 200)
-                .computeSafeInsets(100, 200)
-                .calculateRelativeTo(new Rect(5, 5, 95, 195));
-
-        assertEquals(new Rect(0, 0, 0, 15), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void calculateRelativeTo_right() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(180, 0, 200, 100)
-                .computeSafeInsets(200, 100)
-                .calculateRelativeTo(new Rect(5, 5, 195, 95));
-
-        assertEquals(new Rect(0, 0, 15, 0), cutout.getSafeInsets());
-    }
-
-    @Test
-    public void calculateRelativeTo_bounds() throws Exception {
-        DisplayCutout cutout = fromBoundingRect(0, 0, 100, 20)
-                .computeSafeInsets(200, 400)
-                .calculateRelativeTo(new Rect(5, 10, 95, 180));
-
-        assertEquals(new Rect(-5, -10, 95, 10), cutout.getBounds().getBounds());
+        assertEquals(new Rect(49, -2, 74, 98), cutout.getBounds().getBounds());
     }
 
     @Test
@@ -276,26 +191,26 @@
 
     @Test
     public void fromSpec_caches() {
-        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 1f);
-        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 1f), sameInstance(cached));
+        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f);
+        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), sameInstance(cached));
     }
 
     @Test
     public void fromSpec_wontCacheIfSpecChanges() {
-        DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 1f);
-        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 1f), not(sameInstance(cached)));
+        DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 400, 1f);
+        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
     }
 
     @Test
     public void fromSpec_wontCacheIfScreenWidthChanges() {
-        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 1f);
-        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 1f), not(sameInstance(cached)));
+        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 400, 1f);
+        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
     }
 
     @Test
     public void fromSpec_wontCacheIfDensityChanges() {
-        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 2f);
-        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 1f), not(sameInstance(cached)));
+        DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f);
+        assertThat(fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f), not(sameInstance(cached)));
     }
 
     @Test
@@ -348,7 +263,6 @@
     private static DisplayCutout createCutoutWithInsets(int left, int top, int right, int bottom) {
         return new DisplayCutout(
                 new Rect(left, top, right, bottom),
-                new Region(50, 0, 75, 100),
-                null);
+                Arrays.asList(new Rect(50, 0, 75, 100)));
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
new file mode 100644
index 0000000..b77982b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package android.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SelectionEventTest {
+
+    @Test
+    public void testParcel() {
+        final SelectionEvent[] captured = new SelectionEvent[1];
+        final Logger logger = new Logger(new Logger.Config(
+                InstrumentationRegistry.getTargetContext(), Logger.WIDGET_TEXTVIEW, null)) {
+            @Override
+            public void writeEvent(SelectionEvent event) {
+                captured[0] = event;
+            }
+        };
+        logger.logSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, 0);
+        final SelectionEvent event = captured[0];
+        final Parcel parcel = Parcel.obtain();
+        event.writeToParcel(parcel, event.describeContents());
+        parcel.setDataPosition(0);
+        assertEquals(event, SelectionEvent.CREATOR.createFromParcel(parcel));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index c8994dd..002df88 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
@@ -74,12 +75,12 @@
     }
 
     @Test
-    public void layoutInDisplayCutoutMode_always() throws Exception {
-        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeAlways);
+    public void layoutInDisplayCutoutMode_shortEdges() throws Exception {
+        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeShortEdges);
         installDecor();
 
         assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
-                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS));
+                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES));
     }
 
     @Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
index dece9a4..bcf9490 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
@@ -16,7 +16,7 @@
 
 package com.android.multidexlegacyandexception;
 
-import android.support.multidex.MultiDexApplication;
+import androidx.multidex.MultiDexApplication;
 
 public class TestApplication extends MultiDexApplication {
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
index 758ac1d..92a3b0c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
@@ -17,7 +17,7 @@
 package com.android.multidexlegacyandexception.tests;
 
 import android.os.Bundle;
-import android.support.multidex.MultiDex;
+import androidx.multidex.MultiDex;
 import android.support.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
index c52ad29..f89d132 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
@@ -16,7 +16,7 @@
 
 package com.android.multidexlegacytestapp;
 
-import android.support.multidex.MultiDexApplication;
+import androidx.multidex.MultiDexApplication;
 
 import java.lang.annotation.Annotation;
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
index 963f904..9e41a92 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
@@ -1,7 +1,7 @@
 package com.android.multidexlegacytestapp.test2;
 
 import android.os.Bundle;
-import android.support.multidex.MultiDex;
+import androidx.multidex.MultiDex;
 import android.support.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
index 7993c6f..5f006fe 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
@@ -9,7 +9,7 @@
         android:targetSdkVersion="18" />
 
     <application
-        android:name="android.support.multidex.MultiDexApplication"
+        android:name="androidx.multidex.MultiDexApplication"
         android:allowBackup="true"
         android:label="MultiDexLegacyTestApp_corrupted">
         <activity
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
index cb0a591..bbb4944 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
@@ -20,7 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
-import android.support.multidex.MultiDex;
+import androidx.multidex.MultiDex;
 import android.util.Log;
 
 import java.io.File;
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
index c7b066d..f3f11b9 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
@@ -9,7 +9,7 @@
         android:targetSdkVersion="18" />
 
     <application
-        android:name="android.support.multidex.MultiDexApplication"
+        android:name="androidx.multidex.MultiDexApplication"
         android:allowBackup="true"
         android:label="MultiDexLegacyVersionedTestApp_v1">
         <activity
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
index 4d24793..e43e56b 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
@@ -9,7 +9,7 @@
         android:targetSdkVersion="18" />
 
     <application
-        android:name="android.support.multidex.MultiDexApplication"
+        android:name="androidx.multidex.MultiDexApplication"
         android:allowBackup="true"
         android:label="MultiDexLegacyVersionedTestApp_v2">
         <activity
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
index 76c92dd..1d97228 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
@@ -9,7 +9,7 @@
         android:targetSdkVersion="18" />
 
     <application
-        android:name="android.support.multidex.MultiDexApplication"
+        android:name="androidx.multidex.MultiDexApplication"
         android:allowBackup="true"
         android:label="MultiDexLegacyVersionedTestApp_v3">
         <activity
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 2a3967c..b51c662 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -156,17 +156,6 @@
                 @NonNull List<MediaItem2> playlist) { }
 
         /**
-         * Called when the playback state is changed.
-         *
-         * @param controller the controller for this event
-         * @param state latest playback state
-         * @hide
-         */
-        // TODO(jaewan): Remove (b/73971431)
-        public void onPlaybackStateChanged(@NonNull MediaController2 controller,
-                @NonNull PlaybackState2 state) { }
-
-        /**
          * Called when the player state is changed.
          *
          * @param controller the controller for this event
@@ -647,20 +636,6 @@
     }
 
     /**
-     * Get the lastly cached {@link PlaybackState2} from
-     * {@link ControllerCallback#onPlaybackStateChanged(MediaController2, PlaybackState2)}.
-     * <p>
-     * It may return {@code null} before the first callback or session has sent {@code null}
-     * playback state.
-     *
-     * @return a playback state. Can be {@code null}
-     * @hide
-     */
-    public @Nullable PlaybackState2 getPlaybackState() {
-        return mProvider.getPlaybackState_impl();
-    }
-
-    /**
      * Get the lastly cached player state from
      * {@link ControllerCallback#onPlayerStateChanged(MediaController2, int)}.
      *
@@ -748,7 +723,14 @@
     }
 
     /**
-     * Return playlist from the session.
+     * Returns the cached playlist from
+     * {@link ControllerCallback#onPlaylistChanged(MediaController2, MediaPlaylistAgent, List,
+     * MediaMetadata2)}.
+     * <p>
+     * This list may differ with the list that was specified with
+     * {@link #setPlaylist(List, MediaMetadata2)} depending on the {@link MediaPlaylistAgent}
+     * implementation. Use media items returned here for other playlist agent APIs such as
+     * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
      *
      * @return playlist. Can be {@code null} if the controller doesn't have enough permission.
      */
@@ -758,12 +740,19 @@
 
     /**
      * Sets the playlist.
+     * <p>
+     * Even when the playlist is successfully set, use the playlist returned from
+     * {@link #getPlaylist()} for playlist APIs such as {@link #skipToPlaylistItem(MediaItem2)}.
+     * Otherwise the session in the remote process can't distinguish between media items.
      *
      * @param list playlist
      * @param metadata metadata of the playlist
+     * @see #getPlaylist()
+     * @see ControllerCallback#onPlaylistChanged(
+     *      MediaController2, MediaPlaylistAgent, List, MediaMetadata2)
      */
     public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
-        // TODO(jaewan): Implement (b/74174649)
+        mProvider.setPlaylist_impl(list, metadata);
     }
 
     /**
@@ -772,17 +761,20 @@
      * @param metadata metadata of the playlist
      */
     public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
-        // TODO(jaewan): Implement (b/74174649)
+        mProvider.updatePlaylistMetadata_impl(metadata);
     }
 
     /**
-     * Returns the playlist metadata
+     * Gets the lastly cached playlist playlist metadata either from
+     * {@link ControllerCallback#onPlaylistMetadataChanged(
+     * MediaController2, MediaPlaylistAgent, MediaMetadata2)} or
+     * {@link ControllerCallback#onPlaylistChanged(
+     * MediaController2, MediaPlaylistAgent, List, MediaMetadata2)}.
      *
      * @return metadata metadata of the playlist, or null if none is set
      */
     public @Nullable MediaMetadata2 getPlaylistMetadata() {
-        // TODO(jaewan): Implement (b/74174649)
-        return null;
+        return mProvider.getPlaylistMetadata_impl();
     }
 
     /**
@@ -797,15 +789,14 @@
     }
 
     /**
-     * Inserts the media item to the play list at position index.
+     * Inserts the media item to the playlist at position index.
      * <p>
      * This will not change the currently playing media item.
-     * If index is less than or equal to the current index of the play list,
-     * the current index of the play list will be incremented correspondingly.
+     * If index is less than or equal to the current index of the playlist,
+     * the current index of the playlist will be incremented correspondingly.
      *
      * @param index the index you want to add
      * @param item the media item you want to add
-     * @throws IndexOutOfBoundsException if index is outside play list range
      */
     public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
         mProvider.addPlaylistItem_impl(index, item);
@@ -816,6 +807,8 @@
      *<p>
      * If the item is the currently playing item of the playlist, current playback
      * will be stopped and playback moves to next source in the list.
+     *
+     * @param item the media item you want to add
      */
     public void removePlaylistItem(@NonNull MediaItem2 item) {
         mProvider.removePlaylistItem_impl(item);
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index 2db1392..b50c3e4 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -65,6 +65,13 @@
     }
 
     /**
+     * @hide
+     */
+    public MediaItem2Provider getProvider() {
+        return mProvider;
+    }
+
+    /**
      * Return this object as a bundle to share between processes.
      *
      * @return a new bundle instance
@@ -141,9 +148,7 @@
 
     @Override
     public boolean equals(Object obj) {
-        // TODO(jaewan): Override this. MediaItem2 may have auto-generated srcId when the DSD isn't
-        //               set, and it should be compared for the equals.
-        return super.equals(obj);
+        return mProvider.equals_impl(obj);
     }
 
     /**
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 745eb74d..1aeed6d 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -17,6 +17,8 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -30,7 +32,7 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -367,27 +369,79 @@
 
     private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
 
+    public static final class BitmapParams {
+        private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
+        private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888;
+
+        /**
+         * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888}
+         * as the preferred bitmap config.
+         */
+        public BitmapParams() {}
+
+        /**
+         * Set the preferred bitmap config for the decoder to decode into.
+         *
+         * If not set, or the request cannot be met, the decoder will output
+         * in {@link Bitmap.Config#ARGB_8888} config by default.
+         *
+         * After decode, the actual config used can be retrieved by {@link #getActualConfig()}.
+         *
+         * @param config the preferred bitmap config to use.
+         */
+        public void setPreferredConfig(@NonNull Bitmap.Config config) {
+            if (config == null) {
+                throw new IllegalArgumentException("preferred config can't be null");
+            }
+            inPreferredConfig = config;
+        }
+
+        /**
+         * Retrieve the preferred bitmap config in the params.
+         *
+         * @return the preferred bitmap config.
+         */
+        public @NonNull Bitmap.Config getPreferredConfig() {
+            return inPreferredConfig;
+        }
+
+        /**
+         * Get the actual bitmap config used to decode the bitmap after the decoding.
+         *
+         * @return the actual bitmap config used.
+         */
+        public @NonNull Bitmap.Config getActualConfig() {
+            return outActualConfig;
+        }
+    }
+
     /**
      * This method retrieves a video frame by its index. It should only be called
      * after {@link #setDataSource}.
      *
+     * After the bitmap is returned, you can query the actual parameters that were
+     * used to create the bitmap from the {@code BitmapParams} argument, for instance
+     * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+     *
      * @param frameIndex 0-based index of the video frame. The frame index must be that of
      *        a valid frame. The total number of frames available for retrieval can be queried
      *        via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
+     * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+     *        If null, default config will be chosen.
      *
      * @throws IllegalStateException if the container doesn't contain video or image sequences.
      * @throws IllegalArgumentException if the requested frame index does not exist.
      *
      * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
      *
-     * @see #getFramesAtIndex(int, int)
+     * @see #getFramesAtIndex(int, int, BitmapParams)
      */
-    public Bitmap getFrameAtIndex(int frameIndex) {
-        Bitmap[] bitmaps = getFramesAtIndex(frameIndex, 1);
-        if (bitmaps == null || bitmaps.length < 1) {
+    public Bitmap getFrameAtIndex(int frameIndex, @Nullable BitmapParams params) {
+        List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params);
+        if (bitmaps == null || bitmaps.size() < 1) {
             return null;
         }
-        return bitmaps[0];
+        return bitmaps.get(0);
     }
 
     /**
@@ -395,24 +449,31 @@
      * specified index. It should only be called after {@link #setDataSource}.
      *
      * If the caller intends to retrieve more than one consecutive video frames,
-     * this method is preferred over {@link #getFrameAtIndex(int)} for efficiency.
+     * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency.
+     *
+     * After the bitmaps are returned, you can query the actual parameters that were
+     * used to create the bitmaps from the {@code BitmapParams} argument, for instance
+     * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}.
      *
      * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
      *        must be that of a valid frame. The total number of frames available for retrieval
      *        can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
      * @param numFrames number of consecutive video frames to retrieve. Must be a positive
      *        value. The stream must contain at least numFrames frames starting at frameIndex.
+     * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+     *        If null, default config will be chosen.
      *
      * @throws IllegalStateException if the container doesn't contain video or image sequences.
      * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
      *         stream doesn't contain at least numFrames starting at frameIndex.
 
-     * @return An array of Bitmaps containing the requested video frames. The returned
+     * @return An list of Bitmaps containing the requested video frames. The returned
      *         array could contain less frames than requested if the retrieval fails.
      *
-     * @see #getFrameAtIndex(int)
+     * @see #getFrameAtIndex(int, BitmapParams)
      */
-    public Bitmap[] getFramesAtIndex(int frameIndex, int numFrames) {
+    public List<Bitmap> getFramesAtIndex(
+            int frameIndex, int numFrames, @Nullable BitmapParams params) {
         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
             throw new IllegalStateException("Does not contail video or image sequences");
         }
@@ -424,24 +485,32 @@
             throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
                 + frameIndex + ", " + numFrames);
         }
-        return _getFrameAtIndex(frameIndex, numFrames);
+        return _getFrameAtIndex(frameIndex, numFrames, params);
     }
-    private native Bitmap[] _getFrameAtIndex(int frameIndex, int numFrames);
+    private native List<Bitmap> _getFrameAtIndex(
+            int frameIndex, int numFrames, @Nullable BitmapParams params);
 
     /**
      * This method retrieves a still image by its index. It should only be called
      * after {@link #setDataSource}.
      *
+     * After the bitmap is returned, you can query the actual parameters that were
+     * used to create the bitmap from the {@code BitmapParams} argument, for instance
+     * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+     *
      * @param imageIndex 0-based index of the image, with negative value indicating
      *        the primary image.
+     * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+     *        If null, default config will be chosen.
+     *
      * @throws IllegalStateException if the container doesn't contain still images.
      * @throws IllegalArgumentException if the requested image does not exist.
      *
      * @return the requested still image, or null if the image cannot be retrieved.
      *
-     * @see #getPrimaryImage
+     * @see #getPrimaryImage(BitmapParams)
      */
-    public Bitmap getImageAtIndex(int imageIndex) {
+    public Bitmap getImageAtIndex(int imageIndex, @Nullable BitmapParams params) {
         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
             throw new IllegalStateException("Does not contail still images");
         }
@@ -451,24 +520,31 @@
             throw new IllegalArgumentException("Invalid image index: " + imageCount);
         }
 
-        return _getImageAtIndex(imageIndex);
+        return _getImageAtIndex(imageIndex, params);
     }
 
     /**
      * This method retrieves the primary image of the media content. It should only
      * be called after {@link #setDataSource}.
      *
+     * After the bitmap is returned, you can query the actual parameters that were
+     * used to create the bitmap from the {@code BitmapParams} argument, for instance
+     * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+     *
+     * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+     *        If null, default config will be chosen.
+     *
      * @return the primary image, or null if it cannot be retrieved.
      *
      * @throws IllegalStateException if the container doesn't contain still images.
      *
-     * @see #getImageAtIndex(int)
+     * @see #getImageAtIndex(int, BitmapParams)
      */
-    public Bitmap getPrimaryImage() {
-        return getImageAtIndex(-1);
+    public Bitmap getPrimaryImage(@Nullable BitmapParams params) {
+        return getImageAtIndex(-1, params);
     }
 
-    private native Bitmap _getImageAtIndex(int imageIndex);
+    private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params);
 
     /**
      * Call this method after setDataSource(). This method finds the optional
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 08defbb..ece19b9 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -214,7 +214,8 @@
  *         call returns right away, the actual seek operation may take a while to
  *         finish, especially for audio/video being streamed. When the actual
  *         seek operation completes, the internal player engine calls a user
- *         supplied MediaPlayer2EventCallback.onCallComplete() with {@link #MEDIA_CALL_SEEK_TO}
+ *         supplied MediaPlayer2EventCallback.onCallCompleted() with
+ *         {@link #CALL_COMPLETED_SEEK_TO}
  *         if an MediaPlayer2EventCallback has been registered beforehand via
  *         {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.</li>
  *         <li>Please
@@ -819,7 +820,7 @@
      * of a batch of commands.
      */
     // This is an asynchronous call.
-    public void notifyWhenCommandLabelReached(Object label) { }
+    public void notifyWhenCommandLabelReached(@NonNull Object label) { }
 
     /**
      * Sets the {@link SurfaceHolder} to use for displaying the video
@@ -1051,6 +1052,7 @@
     /**
      * MediaPlayer2 has not been prepared or just has been reset.
      * In this state, MediaPlayer2 doesn't fetch data.
+     * @hide
      */
     public static final int MEDIAPLAYER2_STATE_IDLE = 1;
 
@@ -1058,29 +1060,33 @@
      * MediaPlayer2 has been just prepared.
      * In this state, MediaPlayer2 just fetches data from media source,
      * but doesn't actively render data.
+     * @hide
      */
     public static final int MEDIAPLAYER2_STATE_PREPARED = 2;
 
     /**
      * MediaPlayer2 is paused.
      * In this state, MediaPlayer2 doesn't actively render data.
+     * @hide
      */
     public static final int MEDIAPLAYER2_STATE_PAUSED = 3;
 
     /**
      * MediaPlayer2 is actively playing back data.
+     * @hide
      */
     public static final int MEDIAPLAYER2_STATE_PLAYING = 4;
 
     /**
      * MediaPlayer2 has hit some fatal error and cannot continue playback.
+     * @hide
      */
     public static final int MEDIAPLAYER2_STATE_ERROR = 5;
 
     /**
      * @hide
      */
-    @IntDef({
+    @IntDef(flag = false, prefix = "MEDIAPLAYER2_STATE", value = {
         MEDIAPLAYER2_STATE_IDLE,
         MEDIAPLAYER2_STATE_PREPARED,
         MEDIAPLAYER2_STATE_PAUSED,
@@ -1093,6 +1099,7 @@
      * Gets the current MediaPlayer2 state.
      *
      * @return the current MediaPlayer2 state.
+     * @hide
      */
     public abstract @MediaPlayer2State int getMediaPlayer2State();
 
@@ -1170,8 +1177,7 @@
     public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0;
 
     /** @hide */
-    @IntDef(
-        value = {
+    @IntDef(flag = false, prefix = "PLAYBACK_RATE_AUDIO_MODE", value = {
             PLAYBACK_RATE_AUDIO_MODE_DEFAULT,
             PLAYBACK_RATE_AUDIO_MODE_STRETCH,
             PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
@@ -1276,8 +1282,7 @@
     public static final int SEEK_CLOSEST          = 0x03;
 
     /** @hide */
-    @IntDef(
-        value = {
+    @IntDef(flag = false, prefix = "SEEK", value = {
             SEEK_PREVIOUS_SYNC,
             SEEK_NEXT_SYNC,
             SEEK_CLOSEST_SYNC,
@@ -1302,16 +1307,6 @@
      * If msec is negative, time position zero will be used.
      * If msec is larger than duration, duration will be used.
      * @param mode the mode indicating where exactly to seek to.
-     * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
-     * that has a timestamp earlier than or the same as msec. Use
-     * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
-     * that has a timestamp later than or the same as msec. Use
-     * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
-     * that has a timestamp closest to or the same as msec. Use
-     * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
-     * or may not be a sync frame but is closest to or the same as msec.
-     * {@link #SEEK_CLOSEST} often has larger performance overhead compared
-     * to the other options if there is no sync frame located at msec.
      */
     // This is an asynchronous call.
     public abstract void seekTo(long msec, @SeekMode int mode);
@@ -1753,28 +1748,20 @@
          * @param dsd the DataSourceDesc of this data source
          * @param data the timed metadata sample associated with this event
          */
-        public void onTimedMetaDataAvailable(MediaPlayer2 mp, DataSourceDesc dsd, TimedMetaData data) { }
+        public void onTimedMetaDataAvailable(
+                MediaPlayer2 mp, DataSourceDesc dsd, TimedMetaData data) { }
 
         /**
          * Called to indicate an error.
          *
          * @param mp the MediaPlayer2 the error pertains to
          * @param dsd the DataSourceDesc of this data source
-         * @param what the type of error that has occurred:
-         * <ul>
-         * <li>{@link #MEDIA_ERROR_UNKNOWN}
-         * </ul>
+         * @param what the type of error that has occurred.
          * @param extra an extra code, specific to the error. Typically
          * implementation dependent.
-         * <ul>
-         * <li>{@link #MEDIA_ERROR_IO}
-         * <li>{@link #MEDIA_ERROR_MALFORMED}
-         * <li>{@link #MEDIA_ERROR_UNSUPPORTED}
-         * <li>{@link #MEDIA_ERROR_TIMED_OUT}
-         * <li><code>MEDIA_ERROR_SYSTEM (-2147483648)</code> - low-level system error.
-         * </ul>
          */
-        public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { }
+        public void onError(
+                MediaPlayer2 mp, DataSourceDesc dsd, @MediaError int what, int extra) { }
 
         /**
          * Called to indicate an info or a warning.
@@ -1782,29 +1769,10 @@
          * @param mp the MediaPlayer2 the info pertains to.
          * @param dsd the DataSourceDesc of this data source
          * @param what the type of info or warning.
-         * <ul>
-         * <li>{@link #MEDIA_INFO_UNKNOWN}
-         * <li>{@link #MEDIA_INFO_STARTED_AS_NEXT}
-         * <li>{@link #MEDIA_INFO_VIDEO_RENDERING_START}
-         * <li>{@link #MEDIA_INFO_AUDIO_RENDERING_START}
-         * <li>{@link #MEDIA_INFO_PLAYBACK_COMPLETE}
-         * <li>{@link #MEDIA_INFO_PLAYLIST_END}
-         * <li>{@link #MEDIA_INFO_PREPARED}
-         * <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
-         * <li>{@link #MEDIA_INFO_BUFFERING_START}
-         * <li>{@link #MEDIA_INFO_BUFFERING_END}
-         * <li><code>MEDIA_INFO_NETWORK_BANDWIDTH (703)</code> -
-         *     bandwidth information is available (as <code>extra</code> kbps)
-         * <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
-         * <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
-         * <li>{@link #MEDIA_INFO_METADATA_UPDATE}
-         * <li>{@link #MEDIA_INFO_UNSUPPORTED_SUBTITLE}
-         * <li>{@link #MEDIA_INFO_SUBTITLE_TIMED_OUT}
-         * </ul>
          * @param extra an extra code, specific to the info. Typically
          * implementation dependent.
          */
-        public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { }
+        public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, @MediaInfo int what, int extra) { }
 
         /**
          * Called to acknowledge an API call.
@@ -1812,33 +1780,11 @@
          * @param mp the MediaPlayer2 the call was made on.
          * @param dsd the DataSourceDesc of this data source
          * @param what the enum for the API call.
-         * <ul>
-         * <li>{@link #MEDIA_CALL_ATTACH_AUX_EFFECT}
-         * <li>{@link #MEDIA_CALL_DESELECT_TRACK}
-         * <li>{@link #MEDIA_CALL_LOOP_CURRENT}
-         * <li>{@link #MEDIA_CALL_PAUSE}
-         * <li>{@link #MEDIA_CALL_PLAY}
-         * <li>{@link #MEDIA_CALL_PREPARE}
-         * <li>{@link #MEDIA_CALL_RELEASE_DRM}
-         * <li>{@link #MEDIA_CALL_RESTORE_DRM_KEYS}
-         * <li>{@link #MEDIA_CALL_SEEK_TO}
-         * <li>{@link #MEDIA_CALL_SELECT_TRACK}
-         * <li>{@link #MEDIA_CALL_SET_AUDIO_ATTRIBUTES}
-         * <li>{@link #MEDIA_CALL_SET_AUDIO_SESSION_ID}
-         * <li>{@link #MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL}
-         * <li>{@link #MEDIA_CALL_SET_DATA_SOURCE}
-         * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCE}
-         * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCES}
-         * <li>{@link #MEDIA_CALL_SET_PLAYBACK_PARAMS}
-         * <li>{@link #MEDIA_CALL_SET_PLAYBACK_SPEED}
-         * <li>{@link #MEDIA_CALL_SET_PLAYER_VOLUME}
-         * <li>{@link #MEDIA_CALL_SET_SURFACE}
-         * <li>{@link #MEDIA_CALL_SET_SYNC_PARAMS}
-         * <li>{@link #MEDIA_CALL_SKIP_TO_NEXT}
-         * </ul>
          * @param status the returned status code for the call.
          */
-        public void onCallComplete(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { }
+        public void onCallCompleted(
+                MediaPlayer2 mp, DataSourceDesc dsd, @CallCompleted int what,
+                @CallStatus int status) { }
 
         /**
          * Called to indicate media clock has changed.
@@ -1847,7 +1793,8 @@
          * @param dsd the DataSourceDesc of this data source
          * @param timestamp the new media clock.
          */
-        public void onMediaTimeChanged(MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { }
+        public void onMediaTimeChanged(
+                MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { }
 
         /**
          * Called to indicate {@link #notifyWhenCommandLabelReached(Object)} has been processed.
@@ -1856,7 +1803,7 @@
          * @param label the application specific Object given by
          *        {@link #notifyWhenCommandLabelReached(Object)}.
          */
-        public void onCommandLabelReached(MediaPlayer2 mp, Object label) { }
+        public void onCommandLabelReached(MediaPlayer2 mp, @NonNull Object label) { }
     }
 
     /**
@@ -1929,6 +1876,20 @@
      */
     public static final int MEDIA_ERROR_SYSTEM = -2147483648;
 
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIA_ERROR", value = {
+            MEDIA_ERROR_UNKNOWN,
+            MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
+            MEDIA_ERROR_IO,
+            MEDIA_ERROR_MALFORMED,
+            MEDIA_ERROR_UNSUPPORTED,
+            MEDIA_ERROR_TIMED_OUT,
+            MEDIA_ERROR_SYSTEM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaError {}
 
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer2.h!
@@ -2059,129 +2020,246 @@
      */
     public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
 
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIA_INFO", value = {
+            MEDIA_INFO_UNKNOWN,
+            MEDIA_INFO_STARTED_AS_NEXT,
+            MEDIA_INFO_VIDEO_RENDERING_START,
+            MEDIA_INFO_AUDIO_RENDERING_START,
+            MEDIA_INFO_PLAYBACK_COMPLETE,
+            MEDIA_INFO_PLAYLIST_END,
+            MEDIA_INFO_PREPARED,
+            MEDIA_INFO_VIDEO_TRACK_LAGGING,
+            MEDIA_INFO_BUFFERING_START,
+            MEDIA_INFO_BUFFERING_END,
+            MEDIA_INFO_NETWORK_BANDWIDTH,
+            MEDIA_INFO_BUFFERING_UPDATE,
+            MEDIA_INFO_BAD_INTERLEAVING,
+            MEDIA_INFO_NOT_SEEKABLE,
+            MEDIA_INFO_METADATA_UPDATE,
+            MEDIA_INFO_EXTERNAL_METADATA_UPDATE,
+            MEDIA_INFO_AUDIO_NOT_PLAYING,
+            MEDIA_INFO_VIDEO_NOT_PLAYING,
+            MEDIA_INFO_TIMED_TEXT_ERROR,
+            MEDIA_INFO_UNSUPPORTED_SUBTITLE,
+            MEDIA_INFO_SUBTITLE_TIMED_OUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaInfo {}
+
     //--------------------------------------------------------------------------
     /** The player just completed a call {@link #attachAuxEffect}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1;
+    public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1;
 
     /** The player just completed a call {@link #deselectTrack}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_DESELECT_TRACK = 2;
+    public static final int CALL_COMPLETED_DESELECT_TRACK = 2;
 
     /** The player just completed a call {@link #loopCurrent}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_LOOP_CURRENT = 3;
+    public static final int CALL_COMPLETED_LOOP_CURRENT = 3;
 
     /** The player just completed a call {@link #pause}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_PAUSE = 4;
+    public static final int CALL_COMPLETED_PAUSE = 4;
 
     /** The player just completed a call {@link #play}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_PLAY = 5;
+    public static final int CALL_COMPLETED_PLAY = 5;
 
     /** The player just completed a call {@link #prepare}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_PREPARE = 6;
+    public static final int CALL_COMPLETED_PREPARE = 6;
 
     /** The player just completed a call {@link #releaseDrm}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_RELEASE_DRM = 12;
+    public static final int CALL_COMPLETED_RELEASE_DRM = 12;
 
     /** The player just completed a call {@link #restoreDrmKeys}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13;
+    public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13;
 
     /** The player just completed a call {@link #seekTo}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SEEK_TO = 14;
+    public static final int CALL_COMPLETED_SEEK_TO = 14;
 
     /** The player just completed a call {@link #selectTrack}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SELECT_TRACK = 15;
+    public static final int CALL_COMPLETED_SELECT_TRACK = 15;
 
     /** The player just completed a call {@link #setAudioAttributes}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16;
+    public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16;
 
     /** The player just completed a call {@link #setAudioSessionId}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17;
+    public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17;
 
     /** The player just completed a call {@link #setAuxEffectSendLevel}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18;
+    public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18;
 
     /** The player just completed a call {@link #setDataSource}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_DATA_SOURCE = 19;
+    public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19;
 
     /** The player just completed a call {@link #setNextDataSource}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22;
+    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22;
 
     /** The player just completed a call {@link #setNextDataSources}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23;
+    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23;
 
     /** The player just completed a call {@link #setPlaybackParams}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24;
+    public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24;
 
     /** The player just completed a call {@link #setPlaybackSpeed}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25;
+    public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25;
 
     /** The player just completed a call {@link #setPlayerVolume}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26;
+    public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26;
 
     /** The player just completed a call {@link #setSurface}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_SURFACE = 27;
+    public static final int CALL_COMPLETED_SET_SURFACE = 27;
 
     /** The player just completed a call {@link #setSyncParams}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28;
+    public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28;
 
     /** The player just completed a call {@link #skipToNext}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      */
-    public static final int MEDIA_CALL_SKIP_TO_NEXT = 29;
+    public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29;
 
     /** The player just completed a call {@link #setBufferingParams}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      * @hide
      */
-    public static final int MEDIA_CALL_SET_BUFFERING_PARAMS = 1001;
+    public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 1001;
 
-    /** The player just completed a call {@link #setPreferredDevice}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+    /** The player just completed a call {@code setVideoScalingMode}.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
      * @hide
      */
-    public static final int MEDIA_CALL_SET_PREFERRED_DEVICE = 1002;
+    public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 1002;
 
+    /** The player just completed a call {@code notifyWhenCommandLabelReached}.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCommandLabelReached
+     * @hide
+     */
+    public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED = 1003;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "CALL_COMPLETED", value = {
+            CALL_COMPLETED_ATTACH_AUX_EFFECT,
+            CALL_COMPLETED_DESELECT_TRACK,
+            CALL_COMPLETED_LOOP_CURRENT,
+            CALL_COMPLETED_PAUSE,
+            CALL_COMPLETED_PLAY,
+            CALL_COMPLETED_PREPARE,
+            CALL_COMPLETED_RELEASE_DRM,
+            CALL_COMPLETED_RESTORE_DRM_KEYS,
+            CALL_COMPLETED_SEEK_TO,
+            CALL_COMPLETED_SELECT_TRACK,
+            CALL_COMPLETED_SET_AUDIO_ATTRIBUTES,
+            CALL_COMPLETED_SET_AUDIO_SESSION_ID,
+            CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL,
+            CALL_COMPLETED_SET_DATA_SOURCE,
+            CALL_COMPLETED_SET_NEXT_DATA_SOURCE,
+            CALL_COMPLETED_SET_NEXT_DATA_SOURCES,
+            CALL_COMPLETED_SET_PLAYBACK_PARAMS,
+            CALL_COMPLETED_SET_PLAYBACK_SPEED,
+            CALL_COMPLETED_SET_PLAYER_VOLUME,
+            CALL_COMPLETED_SET_SURFACE,
+            CALL_COMPLETED_SET_SYNC_PARAMS,
+            CALL_COMPLETED_SKIP_TO_NEXT,
+            CALL_COMPLETED_SET_BUFFERING_PARAMS,
+            CALL_COMPLETED_SET_VIDEO_SCALING_MODE,
+            CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallCompleted {}
+
+    /** Status code represents that call is completed without an error.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_NO_ERROR = 0;
+
+    /** Status code represents that call is ended with an unknown error.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_ERROR_UNKNOWN = Integer.MIN_VALUE;
+
+    /** Status code represents that the player is not in valid state for the operation.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_INVALID_OPERATION = 1;
+
+    /** Status code represents that the argument is illegal.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_BAD_VALUE = 2;
+
+    /** Status code represents that the operation is not allowed.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_PERMISSION_DENIED = 3;
+
+    /** Status code represents a file or network related operation error.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_ERROR_IO = 4;
+
+    /** Status code represents that DRM operation is called before preparing a DRM scheme through
+     *  {@link #prepareDrm}.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_NO_DRM_SCHEME = 5;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "CALL_STATUS", value = {
+            CALL_STATUS_NO_ERROR,
+            CALL_STATUS_ERROR_UNKNOWN,
+            CALL_STATUS_INVALID_OPERATION,
+            CALL_STATUS_BAD_VALUE,
+            CALL_STATUS_PERMISSION_DENIED,
+            CALL_STATUS_ERROR_IO,
+            CALL_STATUS_NO_DRM_SCHEME})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallStatus {}
 
     // Modular DRM begin
 
@@ -2238,13 +2316,10 @@
          *
          * @param mp the {@code MediaPlayer2} associated with this callback
          * @param dsd the DataSourceDesc of this data source
-         * @param status the result of DRM preparation which can be
-         * {@link #PREPARE_DRM_STATUS_SUCCESS},
-         * {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR},
-         * {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or
-         * {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}.
+         * @param status the result of DRM preparation.
          */
-        public void onDrmPrepared(MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
+        public void onDrmPrepared(
+                MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
     }
 
     /**
@@ -2288,7 +2363,7 @@
 
 
     /** @hide */
-    @IntDef({
+    @IntDef(flag = false, prefix = "PREPARE_DRM_STATUS", value = {
         PREPARE_DRM_STATUS_SUCCESS,
         PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
         PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index ee1bb50..1c4d898 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -213,18 +213,13 @@
      */
     @Override
     public void play() {
-        synchronized (mTaskLock) {
-            mPendingTasks.add(new Task(MEDIA_CALL_PLAY, false) {
-                @Override
-                int process() {
-                    stayAwake(true);
-                    _start();
-                    // TODO: define public constants for return value (status).
-                    return 0;
-                }
-            });
-            processPendingTask_l();
-        }
+        addTask(new Task(CALL_COMPLETED_PLAY, false) {
+            @Override
+            void process() {
+                stayAwake(true);
+                _start();
+            }
+        });
     }
 
     private native void _start() throws IllegalStateException;
@@ -241,17 +236,12 @@
      */
     @Override
     public void prepare() {
-        synchronized (mTaskLock) {
-            mPendingTasks.add(new Task(MEDIA_CALL_PREPARE, true) {
-                @Override
-                int process() {
-                    _prepare();
-                    // TODO: define public constants for return value (status).
-                    return 0;
-                }
-            });
-            processPendingTask_l();
-        }
+        addTask(new Task(CALL_COMPLETED_PREPARE, true) {
+            @Override
+            void process() {
+                _prepare();
+            }
+        });
     }
 
     public native void _prepare();
@@ -264,8 +254,13 @@
      */
     @Override
     public void pause() {
-        stayAwake(false);
-        _pause();
+        addTask(new Task(CALL_COMPLETED_PAUSE, false) {
+            @Override
+            void process() {
+                stayAwake(false);
+                _pause();
+            }
+        });
     }
 
     private native void _pause() throws IllegalStateException;
@@ -277,7 +272,12 @@
      */
     @Override
     public void skipToNext() {
-        // TODO: switch to next data source and play
+        addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
+            @Override
+            void process() {
+                // TODO: switch to next data source and play
+            }
+        });
     }
 
     /**
@@ -357,14 +357,19 @@
      */
     @Override
     public void setAudioAttributes(@NonNull AudioAttributes attributes) {
-        if (attributes == null) {
-            final String msg = "Cannot set AudioAttributes to null";
-            throw new IllegalArgumentException(msg);
-        }
-        Parcel pattributes = Parcel.obtain();
-        attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
-        setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
-        pattributes.recycle();
+        addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
+            @Override
+            void process() {
+                if (attributes == null) {
+                    final String msg = "Cannot set AudioAttributes to null";
+                    throw new IllegalArgumentException(msg);
+                }
+                Parcel pattributes = Parcel.obtain();
+                attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
+                setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
+                pattributes.recycle();
+            }
+        });
     }
 
     @Override
@@ -384,16 +389,21 @@
      */
     @Override
     public void setDataSource(@NonNull DataSourceDesc dsd) {
-        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
-        // TODO: setDataSource could update exist data source
-        synchronized (mSrcLock) {
-            mCurrentDSD = dsd;
-            mCurrentSrcId = mSrcIdGenerator++;
-            try {
-                handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
-            } catch (IOException e) {
+        addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
+            @Override
+            void process() {
+                Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
+                // TODO: setDataSource could update exist data source
+                synchronized (mSrcLock) {
+                    mCurrentDSD = dsd;
+                    mCurrentSrcId = mSrcIdGenerator++;
+                    try {
+                        handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
+                    } catch (IOException e) {
+                    }
+                }
             }
-        }
+        });
     }
 
     /**
@@ -406,21 +416,25 @@
      */
     @Override
     public void setNextDataSource(@NonNull DataSourceDesc dsd) {
-        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
-
-        synchronized (mSrcLock) {
-            mNextDSDs = new ArrayList<DataSourceDesc>(1);
-            mNextDSDs.add(dsd);
-            mNextSrcId = mSrcIdGenerator++;
-            mNextSourceState = NEXT_SOURCE_STATE_INIT;
-            mNextSourcePlayPending = false;
-        }
-        int state = getMediaPlayer2State();
-        if (state != MEDIAPLAYER2_STATE_IDLE) {
-            synchronized (mSrcLock) {
-                prepareNextDataSource_l();
+        addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
+            @Override
+            void process() {
+                Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
+                synchronized (mSrcLock) {
+                    mNextDSDs = new ArrayList<DataSourceDesc>(1);
+                    mNextDSDs.add(dsd);
+                    mNextSrcId = mSrcIdGenerator++;
+                    mNextSourceState = NEXT_SOURCE_STATE_INIT;
+                    mNextSourcePlayPending = false;
+                }
+                int state = getMediaPlayer2State();
+                if (state != MEDIAPLAYER2_STATE_IDLE) {
+                    synchronized (mSrcLock) {
+                        prepareNextDataSource_l();
+                    }
+                }
             }
-        }
+        });
     }
 
     /**
@@ -432,28 +446,33 @@
      */
     @Override
     public void setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
-        if (dsds == null || dsds.size() == 0) {
-            throw new IllegalArgumentException("data source list cannot be null or empty.");
-        }
-        for (DataSourceDesc dsd : dsds) {
-            if (dsd == null) {
-                throw new IllegalArgumentException(
-                        "DataSourceDesc in the source list cannot be null.");
-            }
-        }
+        addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
+            @Override
+            void process() {
+                if (dsds == null || dsds.size() == 0) {
+                    throw new IllegalArgumentException("data source list cannot be null or empty.");
+                }
+                for (DataSourceDesc dsd : dsds) {
+                    if (dsd == null) {
+                        throw new IllegalArgumentException(
+                                "DataSourceDesc in the source list cannot be null.");
+                    }
+                }
 
-        synchronized (mSrcLock) {
-            mNextDSDs = new ArrayList(dsds);
-            mNextSrcId = mSrcIdGenerator++;
-            mNextSourceState = NEXT_SOURCE_STATE_INIT;
-            mNextSourcePlayPending = false;
-        }
-        int state = getMediaPlayer2State();
-        if (state != MEDIAPLAYER2_STATE_IDLE) {
-            synchronized (mSrcLock) {
-                prepareNextDataSource_l();
+                synchronized (mSrcLock) {
+                    mNextDSDs = new ArrayList(dsds);
+                    mNextSrcId = mSrcIdGenerator++;
+                    mNextSourceState = NEXT_SOURCE_STATE_INIT;
+                    mNextSourcePlayPending = false;
+                }
+                int state = getMediaPlayer2State();
+                if (state != MEDIAPLAYER2_STATE_IDLE) {
+                    synchronized (mSrcLock) {
+                        prepareNextDataSource_l();
+                    }
+                }
             }
-        }
+        });
     }
 
     @Override
@@ -469,8 +488,13 @@
      */
     @Override
     public void loopCurrent(boolean loop) {
-        // TODO: set the looping mode, send notification
-        setLooping(loop);
+        addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
+            @Override
+            void process() {
+                // TODO: set the looping mode, send notification
+                setLooping(loop);
+            }
+        });
     }
 
     private native void setLooping(boolean looping);
@@ -486,8 +510,12 @@
      */
     @Override
     public void setPlaybackSpeed(float speed) {
-        // TODO: send notification
-        setPlaybackParams(getPlaybackParams().setSpeed(speed));
+        addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_SPEED, false) {
+            @Override
+            void process() {
+                _setPlaybackParams(getPlaybackParams().setSpeed(speed));
+            }
+        });
     }
 
     /**
@@ -522,8 +550,12 @@
      */
     @Override
     public void setPlayerVolume(float volume) {
-        // send notification
-        _setVolume(volume, volume);
+        addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
+            @Override
+            void process() {
+                _setVolume(volume, volume);
+            }
+        });
     }
 
     private native void _setVolume(float leftVolume, float rightVolume);
@@ -630,7 +662,17 @@
 
     @Override
     public void notifyWhenCommandLabelReached(Object label) {
-        // TODO: create an entry in command queue
+        addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
+            @Override
+            void process() {
+                synchronized (mEventCbLock) {
+                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+                        cb.first.execute(() -> cb.second.onCommandLabelReached(
+                                MediaPlayer2Impl.this, label));
+                    }
+                }
+            }
+        });
     }
 
     /**
@@ -683,12 +725,17 @@
      */
     @Override
     public void setSurface(Surface surface) {
-        if (mScreenOnWhilePlaying && surface != null) {
-            Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
-        }
-        mSurfaceHolder = null;
-        _setVideoSurface(surface);
-        updateSurfaceScreenOn();
+        addTask(new Task(CALL_COMPLETED_SET_SURFACE, false) {
+            @Override
+            void process() {
+                if (mScreenOnWhilePlaying && surface != null) {
+                    Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
+                }
+                mSurfaceHolder = null;
+                _setVideoSurface(surface);
+                updateSurfaceScreenOn();
+            }
+        });
     }
 
     /**
@@ -712,20 +759,25 @@
      */
     @Override
     public void setVideoScalingMode(int mode) {
-        if (!isVideoScalingModeSupported(mode)) {
-            final String msg = "Scaling mode " + mode + " is not supported";
-            throw new IllegalArgumentException(msg);
-        }
-        Parcel request = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        try {
-            request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
-            request.writeInt(mode);
-            invoke(request, reply);
-        } finally {
-            request.recycle();
-            reply.recycle();
-        }
+        addTask(new Task(CALL_COMPLETED_SET_VIDEO_SCALING_MODE, false) {
+            @Override
+            void process() {
+                if (!isVideoScalingModeSupported(mode)) {
+                    final String msg = "Scaling mode " + mode + " is not supported";
+                    throw new IllegalArgumentException(msg);
+                }
+                Parcel request = Parcel.obtain();
+                Parcel reply = Parcel.obtain();
+                try {
+                    request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
+                    request.writeInt(mode);
+                    invoke(request, reply);
+                } finally {
+                    request.recycle();
+                    reply.recycle();
+                }
+            }
+        });
     }
 
     /**
@@ -735,6 +787,13 @@
     public void clearPendingCommands() {
     }
 
+    private void addTask(Task task) {
+        synchronized (mTaskLock) {
+            mPendingTasks.add(task);
+            processPendingTask_l();
+        }
+    }
+
     @GuardedBy("mTaskLock")
     private void processPendingTask_l() {
         if (mCurrentTask != null) {
@@ -1332,7 +1391,17 @@
      * @hide
      */
     @Override
-    public native void setBufferingParams(@NonNull BufferingParams params);
+    public void setBufferingParams(@NonNull BufferingParams params) {
+        addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) {
+            @Override
+            void process() {
+                Preconditions.checkNotNull(params, "the BufferingParams cannot be null");
+                _setBufferingParams(params);
+            }
+        });
+    }
+
+    private native void _setBufferingParams(@NonNull BufferingParams params);
 
     /**
      * Sets playback rate and audio mode.
@@ -1386,7 +1455,17 @@
      * @throws IllegalArgumentException if params is not supported.
      */
     @Override
-    public native void setPlaybackParams(@NonNull PlaybackParams params);
+    public void setPlaybackParams(@NonNull PlaybackParams params) {
+        addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
+            @Override
+            void process() {
+                Preconditions.checkNotNull(params, "the PlaybackParams cannot be null");
+                _setPlaybackParams(params);
+            }
+        });
+    }
+
+    private native void _setPlaybackParams(@NonNull PlaybackParams params);
 
     /**
      * Gets the playback params, containing the current playback rate.
@@ -1409,7 +1488,17 @@
      * @throws IllegalArgumentException if params are not supported.
      */
     @Override
-    public native void setSyncParams(@NonNull SyncParams params);
+    public void setSyncParams(@NonNull SyncParams params) {
+        addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) {
+            @Override
+            void process() {
+                Preconditions.checkNotNull(params, "the SyncParams cannot be null");
+                _setSyncParams(params);
+            }
+        });
+    }
+
+    private native void _setSyncParams(@NonNull SyncParams params);
 
     /**
      * Gets the A/V sync mode.
@@ -1454,20 +1543,28 @@
      * @throws IllegalArgumentException if the mode is invalid.
      */
     @Override
-    public void seekTo(long msec, @SeekMode int mode) {
-        if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
-            final String msg = "Illegal seek mode: " + mode;
-            throw new IllegalArgumentException(msg);
-        }
-        // TODO: pass long to native, instead of truncating here.
-        if (msec > Integer.MAX_VALUE) {
-            Log.w(TAG, "seekTo offset " + msec + " is too large, cap to " + Integer.MAX_VALUE);
-            msec = Integer.MAX_VALUE;
-        } else if (msec < Integer.MIN_VALUE) {
-            Log.w(TAG, "seekTo offset " + msec + " is too small, cap to " + Integer.MIN_VALUE);
-            msec = Integer.MIN_VALUE;
-        }
-        _seekTo(msec, mode);
+    public void seekTo(final long msec, @SeekMode int mode) {
+        addTask(new Task(CALL_COMPLETED_SEEK_TO, true) {
+            @Override
+            void process() {
+                if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
+                    final String msg = "Illegal seek mode: " + mode;
+                    throw new IllegalArgumentException(msg);
+                }
+                // TODO: pass long to native, instead of truncating here.
+                long posMs = msec;
+                if (posMs > Integer.MAX_VALUE) {
+                    Log.w(TAG, "seekTo offset " + posMs + " is too large, cap to "
+                            + Integer.MAX_VALUE);
+                    posMs = Integer.MAX_VALUE;
+                } else if (posMs < Integer.MIN_VALUE) {
+                    Log.w(TAG, "seekTo offset " + posMs + " is too small, cap to "
+                            + Integer.MIN_VALUE);
+                    posMs = Integer.MIN_VALUE;
+                }
+                _seekTo(posMs, mode);
+            }
+        });
     }
 
     private native final void _seekTo(long msec, int mode);
@@ -1694,7 +1791,16 @@
      * @throws IllegalArgumentException if the sessionId is invalid.
      */
     @Override
-    public native void setAudioSessionId(int sessionId);
+    public void setAudioSessionId(int sessionId) {
+        addTask(new Task(CALL_COMPLETED_SET_AUDIO_SESSION_ID, false) {
+            @Override
+            void process() {
+                _setAudioSessionId(sessionId);
+            }
+        });
+    }
+
+    private native void _setAudioSessionId(int sessionId);
 
     /**
      * Returns the audio session ID.
@@ -1720,7 +1826,16 @@
      * @param effectId system wide unique id of the effect to attach
      */
     @Override
-    public native void attachAuxEffect(int effectId);
+    public void attachAuxEffect(int effectId) {
+        addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) {
+            @Override
+            void process() {
+                _attachAuxEffect(effectId);
+            }
+        });
+    }
+
+    private native void _attachAuxEffect(int effectId);
 
     /**
      * Sets the send level of the player to the attached auxiliary effect.
@@ -1736,7 +1851,12 @@
      */
     @Override
     public void setAuxEffectSendLevel(float level) {
-        _setAuxEffectSendLevel(level);
+        addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) {
+            @Override
+            void process() {
+                _setAuxEffectSendLevel(level);
+            }
+        });
     }
 
     private native void _setAuxEffectSendLevel(float level);
@@ -2475,7 +2595,12 @@
      */
     @Override
     public void selectTrack(int index) {
-        selectOrDeselectTrack(index, true /* select */);
+        addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) {
+            @Override
+            void process() {
+                selectOrDeselectTrack(index, true /* select */);
+            }
+        });
     }
 
     /**
@@ -2494,7 +2619,12 @@
      */
     @Override
     public void deselectTrack(int index) {
-        selectOrDeselectTrack(index, false /* select */);
+        addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) {
+            @Override
+            void process() {
+                selectOrDeselectTrack(index, false /* select */);
+            }
+        });
     }
 
     private void selectOrDeselectTrack(int index, boolean select)
@@ -2697,8 +2827,11 @@
                     }
                 }
                 synchronized (mTaskLock) {
-                    if (mCurrentTask.mMediaCallType == MEDIA_CALL_PREPARE
+                    if (mCurrentTask != null
+                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
+                            && mCurrentTask.mDSD == dsd
                             && mCurrentTask.mNeedToWaitForEventToComplete) {
+                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
                         mCurrentTask = null;
                         processPendingTask_l();
                     }
@@ -2803,10 +2936,13 @@
 
             case MEDIA_SEEK_COMPLETE:
             {
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onCallComplete(
-                                mMediaPlayer, mCurrentDSD, MEDIA_CALL_SEEK_TO, 0));
+                synchronized (mTaskLock) {
+                    if (mCurrentTask != null
+                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
+                            && mCurrentTask.mNeedToWaitForEventToComplete) {
+                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+                        mCurrentTask = null;
+                        processPendingTask_l();
                     }
                 }
             }
@@ -3390,32 +3526,39 @@
     public void releaseDrm()
             throws NoDrmSchemeException
     {
-        Log.v(TAG, "releaseDrm:");
+        addTask(new Task(CALL_COMPLETED_RELEASE_DRM, false) {
+            @Override
+            void process() throws NoDrmSchemeException {
+                synchronized (mDrmLock) {
+                    Log.v(TAG, "releaseDrm:");
 
-        synchronized (mDrmLock) {
-            if (!mActiveDrmScheme) {
-                Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
-                throw new NoDrmSchemeExceptionImpl("releaseDrm: No active DRM scheme to release.");
+                    if (!mActiveDrmScheme) {
+                        Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
+                        throw new NoDrmSchemeExceptionImpl(
+                                "releaseDrm: No active DRM scheme to release.");
+                    }
+
+                    try {
+                        // we don't have the player's state in this layer. The below call raises
+                        // exception if we're in a non-stopped/prepared state.
+
+                        // for cleaning native/mediaserver crypto object
+                        _releaseDrm();
+
+                        // for cleaning client-side MediaDrm object; only called if above has succeeded
+                        cleanDrmObj();
+
+                        mActiveDrmScheme = false;
+                    } catch (IllegalStateException e) {
+                        Log.w(TAG, "releaseDrm: Exception ", e);
+                        throw new IllegalStateException(
+                                "releaseDrm: The player is not in a valid state.");
+                    } catch (Exception e) {
+                        Log.e(TAG, "releaseDrm: Exception ", e);
+                    }
+                }   // synchronized
             }
-
-            try {
-                // we don't have the player's state in this layer. The below call raises
-                // exception if we're in a non-stopped/prepared state.
-
-                // for cleaning native/mediaserver crypto object
-                _releaseDrm();
-
-                // for cleaning client-side MediaDrm object; only called if above has succeeded
-                cleanDrmObj();
-
-                mActiveDrmScheme = false;
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "releaseDrm: Exception ", e);
-                throw new IllegalStateException("releaseDrm: The player is not in a valid state.");
-            } catch (Exception e) {
-                Log.e(TAG, "releaseDrm: Exception ", e);
-            }
-        }   // synchronized
+        });
     }
 
 
@@ -3470,7 +3613,8 @@
         synchronized (mDrmLock) {
             if (!mActiveDrmScheme) {
                 Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
-                throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
+                throw new NoDrmSchemeExceptionImpl(
+                        "getDrmKeyRequest: Has to set a DRM scheme first.");
             }
 
             try {
@@ -3531,7 +3675,8 @@
 
             if (!mActiveDrmScheme) {
                 Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
-                throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
+                throw new NoDrmSchemeExceptionImpl(
+                        "getDrmKeyRequest: Has to set a DRM scheme first.");
             }
 
             try {
@@ -3541,8 +3686,8 @@
 
                 byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
 
-                Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response +
-                        " --> " + keySetResult);
+                Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response
+                        + " --> " + keySetResult);
 
 
                 return keySetResult;
@@ -3570,23 +3715,29 @@
     public void restoreDrmKeys(@NonNull byte[] keySetId)
             throws NoDrmSchemeException
     {
-        Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
+        addTask(new Task(CALL_COMPLETED_RESTORE_DRM_KEYS, false) {
+            @Override
+            void process() throws NoDrmSchemeException {
+                Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
 
-        synchronized (mDrmLock) {
+                synchronized (mDrmLock) {
 
-            if (!mActiveDrmScheme) {
-                Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
-                throw new NoDrmSchemeExceptionImpl("restoreDrmKeys: Has to set a DRM scheme first.");
+                    if (!mActiveDrmScheme) {
+                        Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
+                        throw new NoDrmSchemeExceptionImpl(
+                                "restoreDrmKeys: Has to set a DRM scheme first.");
+                    }
+
+                    try {
+                        mDrmObj.restoreKeys(mDrmSessionId, keySetId);
+                    } catch (Exception e) {
+                        Log.w(TAG, "restoreKeys Exception " + e);
+                        throw e;
+                    }
+
+                }   // synchronized
             }
-
-            try {
-                mDrmObj.restoreKeys(mDrmSessionId, keySetId);
-            } catch (Exception e) {
-                Log.w(TAG, "restoreKeys Exception " + e);
-                throw e;
-            }
-
-        }   // synchronized
+        });
     }
 
 
@@ -3611,7 +3762,8 @@
 
             if (!mActiveDrmScheme && !mDrmConfigAllowed) {
                 Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
-                throw new NoDrmSchemeExceptionImpl("getDrmPropertyString: Has to prepareDrm() first.");
+                throw new NoDrmSchemeExceptionImpl(
+                        "getDrmPropertyString: Has to prepareDrm() first.");
             }
 
             try {
@@ -3649,7 +3801,8 @@
 
             if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
                 Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
-                throw new NoDrmSchemeExceptionImpl("setDrmPropertyString: Has to prepareDrm() first.");
+                throw new NoDrmSchemeExceptionImpl(
+                        "setDrmPropertyString: Has to prepareDrm() first.");
             }
 
             try {
@@ -4587,34 +4740,61 @@
     private abstract class Task implements Runnable {
         private final int mMediaCallType;
         private final boolean mNeedToWaitForEventToComplete;
+        private DataSourceDesc mDSD;
 
         public Task (int mediaCallType, boolean needToWaitForEventToComplete) {
             mMediaCallType = mediaCallType;
             mNeedToWaitForEventToComplete = needToWaitForEventToComplete;
         }
 
-        abstract int process();
+        abstract void process() throws IOException, NoDrmSchemeException;
 
         @Override
         public void run() {
-            int status = process();
+            int status = CALL_STATUS_NO_ERROR;
+            try {
+                process();
+            } catch (IllegalStateException e) {
+                status = CALL_STATUS_INVALID_OPERATION;
+            } catch (IllegalArgumentException e) {
+                status = CALL_STATUS_BAD_VALUE;
+            } catch (SecurityException e) {
+                status = CALL_STATUS_PERMISSION_DENIED;
+            } catch (IOException e) {
+                status = CALL_STATUS_ERROR_IO;
+            } catch (NoDrmSchemeException e) {
+                status = CALL_STATUS_NO_DRM_SCHEME;
+            } catch (Exception e) {
+                status = CALL_STATUS_ERROR_UNKNOWN;
+            }
+            synchronized (mSrcLock) {
+                mDSD = mCurrentDSD;
+            }
 
-            if (!mNeedToWaitForEventToComplete) {
-                final DataSourceDesc dsd;
-                synchronized (mSrcLock) {
-                    dsd = mCurrentDSD;
-                }
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onCallComplete(
-                                MediaPlayer2Impl.this, dsd, mMediaCallType, status));
-                    }
-                }
+            // TODO: Make native implementations asynchronous and let them send notifications.
+            if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
+
+                sendCompleteNotification(status);
+
                 synchronized (mTaskLock) {
                     mCurrentTask = null;
                     processPendingTask_l();
                 }
             }
         }
+
+        private void sendCompleteNotification(int status) {
+            // In {@link #notifyWhenCommandLabelReached} case, a separate callback
+            // {#link #onCommandLabelReached} is already called in {@code process()}.
+            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
+                return;
+            }
+            synchronized (mEventCbLock) {
+                for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+                    cb.first.execute(() -> cb.second.onCallCompleted(
+                            MediaPlayer2Impl.this, mDSD, mMediaCallType, status));
+                }
+            }
+        }
     };
 }
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 65378b4..e60c5f9 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import static android.media.MediaPlayerBase.PLAYER_STATE_IDLE;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -61,7 +63,7 @@
  * sessions can be created to provide finer grain controls of media.
  * <p>
  * If you want to support background playback, {@link MediaSessionService2} is preferred
- * instead. With it, your playback can be revived even after you've finished playback. See
+ * instead. With it, your playback can be revived even after playback is finished. See
  * {@link MediaSessionService2} for details.
  * <p>
  * A session can be obtained by {@link Builder}. The owner of the session may pass its session token
@@ -254,7 +256,7 @@
     public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18;
 
     /**
-     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2).
+     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)}.
      * <p>
      * Command would be sent directly to the playlist agent if the session doesn't reject the
      * request through the
@@ -263,11 +265,8 @@
     public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19;
 
     /**
-     * Command code for {@link MediaController2#getPlaylistMetadata()} ()}. This will expose
+     * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose
      * metadata information to the controller.
-     * *
-     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)} and
-     * {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
      * <p>
      * Command would be sent directly to the playlist agent if the session doesn't reject the
      * request through the
@@ -827,7 +826,11 @@
                 @NonNull MediaPlayerBase player, @NonNull MediaItem2 item, @BuffState int state) { }
 
         /**
-         * Called when a playlist is changed.
+         * Called when a playlist is changed from the {@link MediaPlaylistAgent}.
+         * <p>
+         * This is called when the underlying agent has called
+         * {@link MediaPlaylistAgent.PlaylistEventCallback#onPlaylistChanged(MediaPlaylistAgent,
+         * List, MediaMetadata2)}.
          *
          * @param session the session for this event
          * @param playlistAgent playlist agent for this event
@@ -1638,13 +1641,36 @@
     }
 
     /**
-     * Return the {@link PlaybackState2} from the player.
+     * Get the player state.
      *
-     * @return playback state
+     * @return player state
      * @hide
      */
-    public PlaybackState2 getPlaybackState() {
-        return mProvider.getPlaybackState_impl();
+    public @PlayerState int getPlayerState() {
+        // TODO(jaewan): implement this (b/74578458)
+        return PLAYER_STATE_IDLE;
+    }
+
+    /**
+     * Get the current position.
+     *
+     * @return position
+     * @hide
+     */
+    public long getCurrentPosition() {
+        // TODO(jaewan): implement this (b/74578458)
+        return -1;
+    }
+
+    /**
+     * Get the buffered position.
+     *
+     * @return buffered position
+     * @hide
+     */
+    public long getBufferedPosition() {
+        // TODO(jaewan): implement this (b/74578458)
+        return -1;
     }
 
     /**
@@ -1681,7 +1707,7 @@
      * <p>
      * If it's not set, playback wouldn't happen for the item without data source descriptor.
      * <p>
-     * The helper will be run on the executor that you've specified by the
+     * The helper will be run on the executor that was specified by
      * {@link Builder#setSessionCallback(Executor, SessionCallback)}.
      *
      * @param helper a data source missing helper.
@@ -1705,40 +1731,46 @@
     }
 
     /**
-     * Return the playlist which is lastly set.
+     * Returns the playlist from the {@link MediaPlaylistAgent}.
+     * <p>
+     * This list may differ with the list that was specified with
+     * {@link #setPlaylist(List, MediaMetadata2)} depending on the {@link MediaPlaylistAgent}
+     * implementation. Use media items returned here for other playlist agent APIs such as
+     * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
      *
      * @return playlist
+     * @see MediaPlaylistAgent#getPlaylist()
+     * @see SessionCallback#onPlaylistChanged(
+     *          MediaSession2, MediaPlaylistAgent, List, MediaMetadata2)
      */
     public List<MediaItem2> getPlaylist() {
         return mProvider.getPlaylist_impl();
     }
 
     /**
-     * Set a list of {@link MediaItem2} as the current play list.
-     *
-     * @param playlist A list of {@link MediaItem2} objects to set as a play list.
-     * @throws IllegalArgumentException if given {@param playlist} is null.
-     * @hide
-     */
-    // TODO(jaewan): Remove
-    public void setPlaylist(@NonNull List<MediaItem2> playlist) {
-        mProvider.setPlaylist_impl(playlist);
-    }
-
-    /**
-     * Set a list of {@link MediaItem2} as the current play list. Ensure uniqueness in the
-     * {@link MediaItem2} in the playlist so session can uniquely identity individual items.
+     * Sets a list of {@link MediaItem2} to the {@link MediaPlaylistAgent}. Ensure uniqueness of
+     * each {@link MediaItem2} in the playlist so the session can uniquely identity individual
+     * items.
      * <p>
-     * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. However, in that case,
-     * you should set {@link OnDataSourceMissingHelper} for player to prepare.
+     * This may be an asynchronous call, and {@link MediaPlaylistAgent} may keep the copy of the
+     * list. Wait for {@link SessionCallback#onPlaylistChanged(MediaSession2, MediaPlaylistAgent,
+     * List, MediaMetadata2)} to know the operation finishes.
+     * <p>
+     * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. In that case,
+     * {@link MediaPlaylistAgent} has responsibility to dynamically query {@link DataSourceDesc}
+     * when such media item is ready for preparation or play. Default implementation needs
+     * {@link OnDataSourceMissingHelper} for such case.
      *
      * @param list A list of {@link MediaItem2} objects to set as a play list.
-     * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media item.
+     * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media
+     * items.
+     * @see MediaPlaylistAgent#setPlaylist(List, MediaMetadata2)
+     * @see SessionCallback#onPlaylistChanged(
+     *          MediaSession2, MediaPlaylistAgent, List, MediaMetadata2)
      * @see #setOnDataSourceMissingHelper
      */
     public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
-        // TODO(jaewan): Handle metadata here (b/74174649)
-        // TODO(jaewan): Handle list change (b/74326040)
+        mProvider.setPlaylist_impl(list, metadata);
     }
 
     /**
@@ -1760,13 +1792,17 @@
         mProvider.skipToNextItem_impl();
     }
 
+    /**
+     * Gets the playlist metadata from the {@link MediaPlaylistAgent}.
+     *
+     * @return the playlist metadata
+     */
     public MediaMetadata2 getPlaylistMetadata() {
-        // TODO(jaewan): Implement (b/74174649)
-        return null;
+        return mProvider.getPlaylistMetadata_impl();
     }
 
     /**
-     * Add the media item to the play list at position index.
+     * Adds the media item to the playlist at position index.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the play list,
@@ -1774,26 +1810,25 @@
      *
      * @param index the index you want to add
      * @param item the media item you want to add
-     * @throws IndexOutOfBoundsException if index is outside play list range
      */
     public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
         mProvider.addPlaylistItem_impl(index, item);
     }
 
     /**
-     * Remove the media item in the play list.
+     * Removes the media item in the playlist.
      * <p>
      * If the item is the currently playing item of the playlist, current playback
      * will be stopped and playback moves to next source in the list.
      *
-     * @throws IllegalArgumentException if the play list is null
+     * @param item the media item you want to add
      */
     public void removePlaylistItem(@NonNull MediaItem2 item) {
         mProvider.removePlaylistItem_impl(item);
     }
 
     /**
-     * Replace the media item at index in the playlist. This can be also used to update metadata of
+     * Replaces the media item at index in the playlist. This can be also used to update metadata of
      * an item.
      *
      * @param index the index of the item to replace
@@ -1813,8 +1848,13 @@
         return mProvider.getCurrentPlaylistItem_impl();
     }
 
+    /**
+     * Updates the playlist metadata to the {@link MediaPlaylistAgent}.
+     *
+     * @param metadata metadata of the playlist
+     */
     public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
-        // TODO(jaewan): Implement (b/74174649)
+        mProvider.updatePlaylistMetadata_impl(metadata);
     }
 
     public @RepeatMode int getRepeatMode() {
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
deleted file mode 100644
index afc2bfa..0000000
--- a/media/java/android/media/PlaybackState2.java
+++ /dev/null
@@ -1,217 +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.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.media.update.ApiLoader;
-import android.media.update.PlaybackState2Provider;
-import android.os.Bundle;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Playback state for a {@link MediaPlayerBase}, to be shared between {@link MediaSession2} and
- * {@link MediaController2}. This includes a playback state {@link #STATE_PLAYING},
- * the current playback position and extra.
- * @hide
- */
-// TODO(jaewan): Remove this (b/73971431)
-public final class PlaybackState2 {
-    // Similar to the PlaybackState with following changes
-    //    - Not implement Parcelable and added from/toBundle()
-    //    - Removed playback state that doesn't match with the MediaPlayer2
-    //      Full list should be finalized when the MediaPlayer2 has getter for the playback state.
-    //      Here's table for the MP2 state and PlaybackState2.State.
-    //         +----------------------------------------+----------------------------------------+
-    //         | MediaPlayer2 state                     | Matching PlaybackState2.State          |
-    //         | (Names are from MP2' Javadoc)          |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Idle: Just finished creating MP2       | STATE_NONE                             |
-    //         |     or reset() is called               |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Initialized: setDataSource/Playlist    | N/A (Session/Controller don't          |
-    //         |                                        |     differentiate with Prepared)       |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Prepared: Prepared after initialized   | STATE_PAUSED                           |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Started: Started playback              | STATE_PLAYING                          |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Paused: Paused playback                | STATE_PAUSED                           |
-    //         +----------------------------------------+----------------------------------------+
-    //         | PlaybackCompleted: Playback is done    | STATE_PAUSED                           |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Stopped: MP2.stop() is called.         | STATE_STOPPED                          |
-    //         |     prepare() is needed to play again  |                                        |
-    //         |     (Seemingly the same as initialized |                                        |
-    //         |     because cannot set data source     |                                        |
-    //         |     after this)                        |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Error: an API is called in a state     | STATE_ERROR                            |
-    //         |     that the API isn't supported       |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //         | End: MP2.close() is called to release  | N/A (MediaSession will be gone)        |
-    //         |    MP2. Cannot be reused anymore       |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //         | Started, but                           | STATE_BUFFERING                        |
-    //         |    EventCallback.onBufferingUpdate()   |                                        |
-    //         +----------------------------------------+----------------------------------------+
-    //    - Removed actions and custom actions.
-    //    - Removed error string
-    //    - Repeat mode / shuffle mode is now in the PlaylistParams
-    /**
-     * @hide
-     */
-    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_BUFFERING, STATE_ERROR})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface State {}
-
-    /**
-     * This is the default playback state and indicates that no media has been
-     * added yet, or the performer has been reset and has no content to play.
-     */
-    public final static int STATE_NONE = 0;
-
-    /**
-     * State indicating this item is currently stopped.
-     */
-    public final static int STATE_STOPPED = 1;
-
-    /**
-     * State indicating this item is currently paused.
-     */
-    public final static int STATE_PAUSED = 2;
-
-    /**
-     * State indicating this item is currently playing.
-     */
-    public final static int STATE_PLAYING = 3;
-
-    /**
-     * State indicating this item is currently buffering and will begin playing
-     * when enough data has buffered.
-     */
-    public final static int STATE_BUFFERING = 4;
-
-    /**
-     * State indicating this item is currently in an error state.
-     */
-    public final static int STATE_ERROR = 5;
-
-    /**
-     * Use this value for the position to indicate the position is not known.
-     */
-    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
-
-    private final PlaybackState2Provider mProvider;
-
-    public PlaybackState2(@NonNull Context context, int state, long position, long updateTime,
-            float speed, long bufferedPosition, long activeItemId) {
-        mProvider = ApiLoader.getProvider(context).createPlaybackState2(context, this, state,
-                position, updateTime, speed, bufferedPosition, activeItemId);
-    }
-
-    @Override
-    public String toString() {
-        return mProvider.toString_impl();
-    }
-
-    /**
-     * Get the current state of playback. One of the following:
-     * <ul>
-     * <li> {@link PlaybackState2#STATE_NONE}</li>
-     * <li> {@link PlaybackState2#STATE_STOPPED}</li>
-     * <li> {@link PlaybackState2#STATE_PAUSED}</li>
-     * <li> {@link PlaybackState2#STATE_PLAYING}</li>
-     * <li> {@link PlaybackState2#STATE_BUFFERING}</li>
-     * <li> {@link PlaybackState2#STATE_ERROR}</li>
-     * </ul>
-     */
-    @State
-    public int getState() {
-        return mProvider.getState_impl();
-    }
-
-    /**
-     * Get the current playback position in ms.
-     */
-    public long getPosition() {
-        return mProvider.getPosition_impl();
-    }
-
-    /**
-     * Get the current buffered position in ms. This is the farthest playback
-     * point that can be reached from the current position using only buffered
-     * content.
-     */
-    public long getBufferedPosition() {
-        return mProvider.getBufferedPosition_impl();
-    }
-
-    /**
-     * Get the current playback speed as a multiple of normal playback. This
-     * should be negative when rewinding. A value of 1 means normal playback and
-     * 0 means paused.
-     *
-     * @return The current speed of playback.
-     */
-    public float getPlaybackSpeed() {
-        return mProvider.getPlaybackSpeed_impl();
-    }
-
-    /**
-     * Get the elapsed real time at which position was last updated. If the
-     * position has never been set this will return 0;
-     *
-     * @return The last time the position was updated.
-     */
-    public long getLastPositionUpdateTime() {
-        return mProvider.getLastPositionUpdateTime_impl();
-    }
-
-    /**
-     * Get the id of the currently active item in the playlist.
-     *
-     * @return The id of the currently active item in the queue
-     */
-    public long getCurrentPlaylistItemIndex() {
-        return mProvider.getCurrentPlaylistItemIndex_impl();
-    }
-
-    /**
-     * Returns this object as a bundle to share between processes.
-     */
-    public @NonNull Bundle toBundle() {
-        return mProvider.toBundle_impl();
-    }
-
-    /**
-     * Creates an instance from a bundle which is previously created by {@link #toBundle()}.
-     *
-     * @param context context
-     * @param bundle A bundle created by {@link #toBundle()}.
-     * @return A new {@link PlaybackState2} instance. Returns {@code null} if the given
-     *         {@param bundle} is null, or if the {@param bundle} has no playback state parameters.
-     */
-    public @Nullable static PlaybackState2 fromBundle(@NonNull Context context,
-            @Nullable Bundle bundle) {
-        return ApiLoader.getProvider(context).fromBundle_PlaybackState2(context, bundle);
-    }
-}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6b130cc..051321c 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -775,8 +775,7 @@
                         public void run() {
                             final Context context = mContext;
                             if (context != null) {
-                                ArrayList<MediaController> controllers
-                                        = new ArrayList<MediaController>();
+                                ArrayList<MediaController> controllers = new ArrayList<>();
                                 int size = tokens.size();
                                 for (int i = 0; i < size; i++) {
                                     controllers.add(new MediaController(context, tokens.get(i)));
@@ -814,10 +813,16 @@
         private final ISessionTokensListener.Stub mStub = new ISessionTokensListener.Stub() {
             @Override
             public void onSessionTokensChanged(final List<Bundle> bundles) {
-                mExecutor.execute(() -> {
-                    List<SessionToken2> tokens = toTokenList(mContext, bundles);
-                    mListener.onSessionTokensChanged(tokens);
-                });
+                final Executor executor = mExecutor;
+                if (executor != null) {
+                    executor.execute(() -> {
+                        final Context context = mContext;
+                        final OnSessionTokensChangedListener listener = mListener;
+                        if (context != null && listener != null) {
+                            listener.onSessionTokensChanged(toTokenList(context, bundles));
+                        }
+                    });
+                }
             }
         };
 
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index 06e9544..55672b6 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -16,14 +16,13 @@
 
 package android.media.update;
 
-import android.annotation.NonNull;
 import android.app.PendingIntent;
 import android.media.AudioAttributes;
 import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
+import android.media.MediaMetadata2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.PlaylistParams;
-import android.media.PlaybackState2;
 import android.media.Rating2;
 import android.media.SessionToken2;
 import android.net.Uri;
@@ -58,6 +57,9 @@
     void setRating_impl(String mediaId, Rating2 rating);
     void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb);
     List<MediaItem2> getPlaylist_impl();
+    void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
+    MediaMetadata2 getPlaylistMetadata_impl();
+    void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
 
     void addPlaylistItem_impl(int index, MediaItem2 item);
     void replacePlaylistItem_impl(int index, MediaItem2 item);
@@ -65,7 +67,6 @@
 
     PlaylistParams getPlaylistParams_impl();
     void setPlaylistParams_impl(PlaylistParams params);
-    PlaybackState2 getPlaybackState_impl();
     int getPlayerState_impl();
     long getPosition_impl();
     float getPlaybackSpeed_impl();
diff --git a/media/java/android/media/update/MediaItem2Provider.java b/media/java/android/media/update/MediaItem2Provider.java
index b494f9e..47db22f 100644
--- a/media/java/android/media/update/MediaItem2Provider.java
+++ b/media/java/android/media/update/MediaItem2Provider.java
@@ -35,6 +35,7 @@
     MediaMetadata2 getMetadata_impl();
     String getMediaId_impl();
     DataSourceDesc getDataSourceDesc_impl();
+    boolean equals_impl(Object obj);
 
     interface BuilderProvider {
         Builder setMediaId_impl(String mediaId);
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 142650a..84ea369 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -47,6 +47,8 @@
     void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
             VolumeProvider2 volumeProvider);
     MediaPlayerBase getPlayer_impl();
+    MediaMetadata2 getPlaylistMetadata_impl();
+    void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
     MediaPlaylistAgent getPlaylistAgent_impl();
     VolumeProvider2 getVolumeProvider_impl();
     SessionToken2 getToken_impl();
@@ -57,12 +59,11 @@
     void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
             ResultReceiver receiver);
     void sendCustomCommand_impl(Command command, Bundle args);
-    void setPlaylist_impl(List<MediaItem2> playlist);
     void addPlaylistItem_impl(int index, MediaItem2 item);
     void removePlaylistItem_impl(MediaItem2 item);
-    void editPlaylistItem_impl(MediaItem2 item);
     void replacePlaylistItem_impl(int index, MediaItem2 item);
     List<MediaItem2> getPlaylist_impl();
+    void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
     MediaItem2 getCurrentPlaylistItem_impl();
     void setPlaylistParams_impl(PlaylistParams params);
     PlaylistParams getPlaylistParams_impl();
diff --git a/media/java/android/media/update/MediaSessionService2Provider.java b/media/java/android/media/update/MediaSessionService2Provider.java
index 8697e70..5eb6254 100644
--- a/media/java/android/media/update/MediaSessionService2Provider.java
+++ b/media/java/android/media/update/MediaSessionService2Provider.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.media.MediaSession2;
 import android.media.MediaSessionService2.MediaNotification;
-import android.media.PlaybackState2;
 import android.os.IBinder;
 
 /**
diff --git a/media/java/android/media/update/PlaybackState2Provider.java b/media/java/android/media/update/PlaybackState2Provider.java
deleted file mode 100644
index 66b8fa5..0000000
--- a/media/java/android/media/update/PlaybackState2Provider.java
+++ /dev/null
@@ -1,40 +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.update;
-
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public interface PlaybackState2Provider {
-    String toString_impl();
-
-    int getState_impl();
-
-    long getPosition_impl();
-
-    long getBufferedPosition_impl();
-
-    float getPlaybackSpeed_impl();
-
-    long getLastPositionUpdateTime_impl();
-
-    long getCurrentPlaylistItemIndex_impl();
-
-    Bundle toBundle_impl();
-}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 53ced9c..f78d4a4 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
-import android.media.DataSourceDesc;
 import android.media.MediaBrowser2;
 import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaController2;
@@ -32,12 +31,10 @@
 import android.media.MediaMetadata2;
 import android.media.MediaPlaylistAgent;
 import android.media.MediaSession2;
-import android.media.MediaSession2.CommandButton.Builder;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
 import android.media.MediaSessionService2.MediaNotification;
-import android.media.PlaybackState2;
 import android.media.Rating2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
@@ -132,10 +129,6 @@
     Rating2 newStarRating_Rating2(Context context, int starRatingStyle, float starRating);
     Rating2 newPercentageRating_Rating2(Context context, float percent);
 
-    PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance, int state,
-            long position, long updateTime, float speed, long bufferedPosition, long activeItemId);
-    PlaybackState2 fromBundle_PlaybackState2(Context context, Bundle bundle);
-
     MediaPlaylistAgentProvider createMediaPlaylistAgent(Context context,
             MediaPlaylistAgent instance);
 }
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index a3fb071..eb03ca7 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -17,7 +17,6 @@
 package android.media.update;
 
 import android.media.MediaItem2;
-import android.media.PlaybackState2;
 
 /**
  * @hide
@@ -34,6 +33,4 @@
     void rewind_impl();
     void seekTo_impl(long pos);
     void skipToPlaylistItem_impl(MediaItem2 item);
-
-    PlaybackState2 getPlaybackState_impl();
 }
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index ff854c5..3a67142 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -25,6 +25,7 @@
 #include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
 #include <media/mediascanner.h>
+#include <nativehelper/ScopedLocalRef.h>
 #include <private/media/VideoFrame.h>
 
 #include "jni.h"
@@ -45,6 +46,12 @@
     jmethodID createScaledBitmapMethod;
     jclass configClazz;  // Must be a global ref
     jmethodID createConfigMethod;
+    jclass bitmapParamsClazz; // Must be a global ref
+    jfieldID inPreferredConfig;
+    jfieldID outActualConfig;
+    jclass arrayListClazz; // Must be a global ref
+    jmethodID arrayListInit;
+    jmethodID arrayListAdd;
 };
 
 static fields_t fields;
@@ -254,16 +261,18 @@
 }
 
 static jobject getBitmapFromVideoFrame(
-        JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height) {
+        JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height,
+        SkColorType outColorType) {
     ALOGV("getBitmapFromVideoFrame: dimension = %dx%d and bytes = %d",
             videoFrame->mDisplayWidth,
             videoFrame->mDisplayHeight,
             videoFrame->mSize);
 
-    jobject config = env->CallStaticObjectMethod(
-                        fields.configClazz,
-                        fields.createConfigMethod,
-                        GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
+    ScopedLocalRef<jobject> config(env,
+            env->CallStaticObjectMethod(
+                    fields.configClazz,
+                    fields.createConfigMethod,
+                    GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
 
     uint32_t width, height, displayWidth, displayHeight;
     bool swapWidthAndHeight = false;
@@ -285,7 +294,7 @@
                             fields.createBitmapMethod,
                             width,
                             height,
-                            config);
+                            config.get());
     if (jBitmap == NULL) {
         if (env->ExceptionCheck()) {
             env->ExceptionClear();
@@ -297,11 +306,19 @@
     SkBitmap bitmap;
     GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
 
-    rotate((uint16_t*)bitmap.getPixels(),
-           (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
-           videoFrame->mWidth,
-           videoFrame->mHeight,
-           videoFrame->mRotationAngle);
+    if (outColorType == kRGB_565_SkColorType) {
+        rotate((uint16_t*)bitmap.getPixels(),
+               (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
+               videoFrame->mWidth,
+               videoFrame->mHeight,
+               videoFrame->mRotationAngle);
+    } else {
+        rotate((uint32_t*)bitmap.getPixels(),
+               (uint32_t*)((char*)videoFrame + sizeof(VideoFrame)),
+               videoFrame->mWidth,
+               videoFrame->mHeight,
+               videoFrame->mRotationAngle);
+    }
 
     if (dst_width <= 0 || dst_height <= 0) {
         dst_width = displayWidth;
@@ -323,12 +340,46 @@
                                 dst_width,
                                 dst_height,
                                 true);
+
+        env->DeleteLocalRef(jBitmap);
         return scaledBitmap;
     }
 
     return jBitmap;
 }
 
+static int getColorFormat(JNIEnv *env, jobject options) {
+    if (options == NULL) {
+        return HAL_PIXEL_FORMAT_RGBA_8888;
+    }
+
+    ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
+    SkColorType prefColorType = GraphicsJNI::getNativeBitmapColorType(env, inConfig.get());
+
+    if (prefColorType == kRGB_565_SkColorType) {
+        return HAL_PIXEL_FORMAT_RGB_565;
+    }
+    return HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
+static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options) {
+    SkColorType outColorType = kN32_SkColorType;
+    if (colorFormat == HAL_PIXEL_FORMAT_RGB_565) {
+        outColorType = kRGB_565_SkColorType;
+    }
+
+    if (options != NULL) {
+        ScopedLocalRef<jobject> config(env,
+                env->CallStaticObjectMethod(
+                        fields.configClazz,
+                        fields.createConfigMethod,
+                        GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
+
+        env->SetObjectField(options, fields.outActualConfig, config.get());
+    }
+    return outColorType;
+}
+
 static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
         JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
 {
@@ -351,11 +402,11 @@
         return NULL;
     }
 
-    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height);
+    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType);
 }
 
 static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
-        JNIEnv *env, jobject thiz, jint index)
+        JNIEnv *env, jobject thiz, jint index, jobject params)
 {
     ALOGV("getImageAtIndex: index %d", index);
     sp<MediaMetadataRetriever> retriever = getRetriever(env, thiz);
@@ -364,9 +415,11 @@
         return NULL;
     }
 
+    int colorFormat = getColorFormat(env, params);
+
     // Call native method to retrieve an image
     VideoFrame *videoFrame = NULL;
-    sp<IMemory> frameMemory = retriever->getImageAtIndex(index);
+    sp<IMemory> frameMemory = retriever->getImageAtIndex(index, colorFormat);
     if (frameMemory != 0) {  // cast the shared structure to a VideoFrame object
         videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
     }
@@ -375,11 +428,13 @@
         return NULL;
     }
 
-    return getBitmapFromVideoFrame(env, videoFrame, -1, -1);
+    SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
+    return getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
 }
 
-static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
-        JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames)
+static jobject android_media_MediaMetadataRetriever_getFrameAtIndex(
+        JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames, jobject params)
 {
     ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d", frameIndex, numFrames);
     sp<MediaMetadataRetriever> retriever = getRetriever(env, thiz);
@@ -389,31 +444,34 @@
         return NULL;
     }
 
+    int colorFormat = getColorFormat(env, params);
+
     std::vector<sp<IMemory> > frames;
-    status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames);
+    status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames, colorFormat);
     if (err != OK || frames.size() == 0) {
         ALOGE("failed to get frames from retriever, err=%d, size=%zu",
                 err, frames.size());
         return NULL;
     }
-
-    jobjectArray bitmapArrayObj = env->NewObjectArray(
-            frames.size(), fields.bitmapClazz, NULL);
-    if (bitmapArrayObj == NULL) {
-        ALOGE("can't create bitmap array object");
+    jobject arrayList = env->NewObject(fields.arrayListClazz, fields.arrayListInit);
+    if (arrayList == NULL) {
+        ALOGE("can't create bitmap array list object");
         return NULL;
     }
 
+    SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
     for (size_t i = 0; i < frames.size(); i++) {
         if (frames[i] == NULL || frames[i]->pointer() == NULL) {
             ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
             continue;
         }
         VideoFrame *videoFrame = static_cast<VideoFrame *>(frames[i]->pointer());
-        jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1);
-        env->SetObjectArrayElement(bitmapArrayObj, i, bitmapObj);
+        jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+        env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
+        env->DeleteLocalRef(bitmapObj);
     }
-    return bitmapArrayObj;
+    return arrayList;
 }
 
 static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
@@ -488,21 +546,21 @@
 // first time an instance of this class is used.
 static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
 {
-    jclass clazz = env->FindClass(kClassPathName);
-    if (clazz == NULL) {
+    ScopedLocalRef<jclass> clazz(env, env->FindClass(kClassPathName));
+    if (clazz.get() == NULL) {
         return;
     }
 
-    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
+    fields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
     if (fields.context == NULL) {
         return;
     }
 
-    jclass bitmapClazz = env->FindClass("android/graphics/Bitmap");
-    if (bitmapClazz == NULL) {
+    clazz.reset(env->FindClass("android/graphics/Bitmap"));
+    if (clazz.get() == NULL) {
         return;
     }
-    fields.bitmapClazz = (jclass) env->NewGlobalRef(bitmapClazz);
+    fields.bitmapClazz = (jclass) env->NewGlobalRef(clazz.get());
     if (fields.bitmapClazz == NULL) {
         return;
     }
@@ -521,11 +579,11 @@
         return;
     }
 
-    jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
-    if (configClazz == NULL) {
+    clazz.reset(env->FindClass("android/graphics/Bitmap$Config"));
+    if (clazz.get() == NULL) {
         return;
     }
-    fields.configClazz = (jclass) env->NewGlobalRef(configClazz);
+    fields.configClazz = (jclass) env->NewGlobalRef(clazz.get());
     if (fields.configClazz == NULL) {
         return;
     }
@@ -535,6 +593,42 @@
     if (fields.createConfigMethod == NULL) {
         return;
     }
+
+    clazz.reset(env->FindClass("android/media/MediaMetadataRetriever$BitmapParams"));
+    if (clazz.get() == NULL) {
+        return;
+    }
+    fields.bitmapParamsClazz = (jclass) env->NewGlobalRef(clazz.get());
+    if (fields.bitmapParamsClazz == NULL) {
+        return;
+    }
+    fields.inPreferredConfig = env->GetFieldID(fields.bitmapParamsClazz,
+            "inPreferredConfig", "Landroid/graphics/Bitmap$Config;");
+    if (fields.inPreferredConfig == NULL) {
+        return;
+    }
+    fields.outActualConfig = env->GetFieldID(fields.bitmapParamsClazz,
+            "outActualConfig", "Landroid/graphics/Bitmap$Config;");
+    if (fields.outActualConfig == NULL) {
+        return;
+    }
+
+    clazz.reset(env->FindClass("java/util/ArrayList"));
+    if (clazz.get() == NULL) {
+        return;
+    }
+    fields.arrayListClazz = (jclass) env->NewGlobalRef(clazz.get());
+    if (fields.arrayListClazz == NULL) {
+        return;
+    }
+    fields.arrayListInit = env->GetMethodID(clazz.get(), "<init>", "()V");
+    if (fields.arrayListInit == NULL) {
+        return;
+    }
+    fields.arrayListAdd = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
+    if (fields.arrayListAdd == NULL) {
+        return;
+    }
 }
 
 static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
@@ -556,17 +650,36 @@
             (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
         },
 
-        {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
-        {"_setDataSource",   "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
-        {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
-        {"_getImageAtIndex", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getImageAtIndex},
-        {"_getFrameAtIndex", "(II)[Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtIndex},
-        {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
-        {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
-        {"release",         "()V", (void *)android_media_MediaMetadataRetriever_release},
-        {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
-        {"native_setup",    "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
-        {"native_init",     "()V", (void *)android_media_MediaMetadataRetriever_native_init},
+        {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V",
+                (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
+        {"_setDataSource",   "(Landroid/media/MediaDataSource;)V",
+                (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
+        {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;",
+                (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
+        {
+            "_getImageAtIndex",
+            "(ILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;",
+            (void *)android_media_MediaMetadataRetriever_getImageAtIndex
+        },
+
+        {
+            "_getFrameAtIndex",
+            "(IILandroid/media/MediaMetadataRetriever$BitmapParams;)Ljava/util/List;",
+            (void *)android_media_MediaMetadataRetriever_getFrameAtIndex
+        },
+
+        {"extractMetadata", "(I)Ljava/lang/String;",
+                (void *)android_media_MediaMetadataRetriever_extractMetadata},
+        {"getEmbeddedPicture", "(I)[B",
+                (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
+        {"release",         "()V",
+                (void *)android_media_MediaMetadataRetriever_release},
+        {"native_finalize", "()V",
+                (void *)android_media_MediaMetadataRetriever_native_finalize},
+        {"native_setup",    "()V",
+                (void *)android_media_MediaMetadataRetriever_native_setup},
+        {"native_init",     "()V",
+                (void *)android_media_MediaMetadataRetriever_native_init},
 };
 
 // This function only registers the native methods, and is called from
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 918b82b..918a375 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1489,7 +1489,7 @@
     {"nativePlayNextDataSource", "(J)V",                        (void *)android_media_MediaPlayer2_playNextDataSource},
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer2_setVideoSurface},
     {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
-    {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
+    {"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
     {"_prepare",            "()V",                              (void *)android_media_MediaPlayer2_prepare},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer2_start},
     {"_stop",               "()V",                              (void *)android_media_MediaPlayer2_stop},
@@ -1497,9 +1497,9 @@
     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer2_getVideoWidth},
     {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer2_getVideoHeight},
     {"native_getMetrics",   "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
-    {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
+    {"_setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
     {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer2_getPlaybackParams},
-    {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer2_setSyncParams},
+    {"_setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer2_setSyncParams},
     {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer2_getSyncParams},
     {"_seekTo",             "(JI)V",                            (void *)android_media_MediaPlayer2_seekTo},
     {"_notifyAt",           "(J)V",                             (void *)android_media_MediaPlayer2_notifyAt},
@@ -1522,9 +1522,9 @@
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer2_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer2_native_finalize},
     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer2_get_audio_session_id},
-    {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer2_set_audio_session_id},
+    {"_setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer2_set_audio_session_id},
     {"_setAuxEffectSendLevel", "(F)V",                          (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
-    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer2_attachAuxEffect},
+    {"_attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer2_attachAuxEffect},
     // Modular DRM
     { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer2_prepareDrm },
     { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer2_releaseDrm },
diff --git a/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
new file mode 100644
index 0000000..6552296
--- /dev/null
+++ b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
@@ -0,0 +1,52 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/zen_duration_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:fillViewport ="true"
+            android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/zen_duration_dialog_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <com.android.settingslib.notification.ZenRadioLayout
+            android:id="@+id/zen_duration_conditions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginEnd="4dp"
+            android:layout_marginStart="4dp"
+            android:paddingBottom="4dp"
+            android:orientation="horizontal">
+            <RadioGroup
+                android:id="@+id/zen_radio_buttons"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+            <LinearLayout
+                android:id="@+id/zen_radio_buttons_content"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:orientation="vertical"/>
+        </com.android.settingslib.notification.ZenRadioLayout>
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 72d7bfa..e77db82 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1062,10 +1062,13 @@
     <!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_manual_zen_less_time">Less time.</string>
 
-    <!--  Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
-    <string name="zen_mode_enable_dialog_turn_on">Turn on</string>
     <!-- Button label for generic cancel action [CHAR LIMIT=20] -->
     <string name="cancel">Cancel</string>
+    <!-- Button label for generic OK action [CHAR LIMIT=20] -->
+    <string name="okay">OK</string>
+
+    <!--  Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
+    <string name="zen_mode_enable_dialog_turn_on">Turn on</string>
     <!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]-->
     <string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string>
     <!-- Sound: Summary for the Do not Disturb option when there is no automatic rules turned on. [CHAR LIMIT=NONE]-->
@@ -1083,4 +1086,8 @@
     <!-- Alarm template for far in the future alarms [CHAR LIMIT=25] -->
     <string name="alarm_template_far">on <xliff:g id="when" example="Fri 7:00 AM">%1$s</xliff:g></string>
 
+    <!-- Do not disturb: Title for the dnd duration setting (user can specify how long dnd will last when toggling dnd on from qs or settings) [CHAR LIMIT=30] -->
+    <string name="zen_mode_duration_settings_title">Duration</string>
+    <!-- Do not disturb: Duration option to always prompt for the duration of dnd -->
+    <string name="zen_mode_duration_always_prompt_title">Ask every time</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 61e113b..56a242a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,7 +1,6 @@
 package com.android.settingslib;
 
 import android.annotation.ColorInt;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -142,7 +141,7 @@
     public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
         final int iconSize = UserIconDrawable.getSizeForList(context);
         if (user.isManagedProfile()) {
-            Drawable drawable =  UserIconDrawable.getManagedUserBadgeDrawable(context);
+            Drawable drawable =  UserIconDrawable.getManagedUserDrawable(context);
             drawable.setBounds(0, 0, iconSize, iconSize);
             return drawable;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 7f469b5..54d1aba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.drawable;
 
+import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
@@ -36,6 +37,7 @@
 import android.graphics.Shader;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
 
 import com.android.settingslib.R;
 
@@ -69,15 +71,23 @@
     private float mBadgeMargin;
 
     /**
-     * Gets the system default managed-user badge as a drawable
+     * Gets the system default managed-user badge as a drawable. This drawable is tint-able.
+     * For badging purpose, consider
+     * {@link android.content.pm.PackageManager#getUserBadgedDrawableForDensity(Drawable, UserHandle, Rect, int)}.
+     *
      * @param context
      * @return drawable containing just the badge
      */
-    public static Drawable getManagedUserBadgeDrawable(Context context) {
-        int displayDensity = context.getResources().getDisplayMetrics().densityDpi;
+    public static Drawable getManagedUserDrawable(Context context) {
+        return getDrawableForDisplayDensity
+                (context, com.android.internal.R.drawable.ic_corp_user_badge);
+    }
+
+    private static Drawable getDrawableForDisplayDensity(
+            Context context, @DrawableRes int drawable) {
+        int density = context.getResources().getDisplayMetrics().densityDpi;
         return context.getResources().getDrawableForDensity(
-                com.android.internal.R.drawable.ic_corp_user_badge,
-                displayDensity, context.getTheme());
+                drawable, density, context.getTheme());
     }
 
     /**
@@ -164,7 +174,8 @@
         boolean isManaged = context.getSystemService(DevicePolicyManager.class)
                 .getProfileOwnerAsUser(userId) != null;
         if (isManaged) {
-            badge = getManagedUserBadgeDrawable(context);
+            badge = getDrawableForDisplayDensity(
+                    context, com.android.internal.R.drawable.ic_corp_badge_case);
         }
         return setBadge(badge);
     }
@@ -322,7 +333,6 @@
                     mIntrinsicRadius, mIconPaint);
             canvas.restoreToCount(saveId);
         }
-
         if (mFrameColor != null) {
             mFramePaint.setColor(mFrameColor.getColorForState(getState(), Color.TRANSPARENT));
         }
@@ -343,7 +353,6 @@
             final float borderRadius = mBadge.getBounds().width() * 0.5f + mBadgeMargin;
             canvas.drawCircle(badgeLeft + mBadgeRadius, badgeTop + mBadgeRadius,
                     borderRadius, mClearPaint);
-
             mBadge.draw(canvas);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
new file mode 100644
index 0000000..7369ba8
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.notification;
+
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.support.annotation.VisibleForTesting;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.policy.PhoneWindow;
+import com.android.settingslib.R;
+
+import java.util.Arrays;
+
+public class ZenDurationDialog {
+    private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
+    @VisibleForTesting protected static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
+    @VisibleForTesting protected static final int MAX_BUCKET_MINUTES =
+            MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
+    private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
+    @VisibleForTesting protected int mBucketIndex = -1;
+
+    @VisibleForTesting protected static final int FOREVER_CONDITION_INDEX = 0;
+    @VisibleForTesting protected static final int COUNTDOWN_CONDITION_INDEX = 1;
+    @VisibleForTesting protected static final int ALWAYS_ASK_CONDITION_INDEX = 2;
+
+    @VisibleForTesting protected Context mContext;
+    @VisibleForTesting protected LinearLayout mZenRadioGroupContent;
+    private RadioGroup mZenRadioGroup;
+    private int MAX_MANUAL_DND_OPTIONS = 3;
+
+    @VisibleForTesting protected LayoutInflater mLayoutInflater;
+
+    public ZenDurationDialog(Context context) {
+        mContext = context;
+    }
+
+    public Dialog createDialog() {
+        int zenDuration = Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_FOREVER);
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
+                .setTitle(R.string.zen_mode_duration_settings_title)
+                .setNegativeButton(R.string.cancel, null)
+                .setPositiveButton(R.string.okay,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                updateZenDuration(zenDuration);
+                            }
+                        });
+
+        View contentView = getContentView();
+        setupRadioButtons(zenDuration);
+        builder.setView(contentView);
+        return builder.create();
+    }
+
+    @VisibleForTesting
+    protected void updateZenDuration(int currZenDuration) {
+        final int checkedRadioButtonId = mZenRadioGroup.getCheckedRadioButtonId();
+
+        int newZenDuration = Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_FOREVER);
+        switch (checkedRadioButtonId) {
+            case FOREVER_CONDITION_INDEX:
+                newZenDuration = Settings.Global.ZEN_DURATION_FOREVER;
+                MetricsLogger.action(mContext,
+                        MetricsProto.MetricsEvent.
+                                NOTIFICATION_ZEN_MODE_DURATION_FOREVER);
+                break;
+            case COUNTDOWN_CONDITION_INDEX:
+                ConditionTag tag = getConditionTagAt(checkedRadioButtonId);
+                newZenDuration = tag.countdownZenDuration;
+                MetricsLogger.action(mContext,
+                        MetricsProto.MetricsEvent.
+                                NOTIFICATION_ZEN_MODE_DURATION_TIME,
+                        newZenDuration);
+                break;
+            case ALWAYS_ASK_CONDITION_INDEX:
+                newZenDuration = Settings.Global.ZEN_DURATION_PROMPT;
+                MetricsLogger.action(mContext,
+                        MetricsProto.MetricsEvent.
+                                NOTIFICATION_ZEN_MODE_DURATION_PROMPT);
+                break;
+        }
+
+        if (currZenDuration != newZenDuration) {
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.ZEN_DURATION, newZenDuration);
+        }
+    }
+
+    @VisibleForTesting
+    protected View getContentView() {
+        if (mLayoutInflater == null) {
+            mLayoutInflater = new PhoneWindow(mContext).getLayoutInflater();
+        }
+        View contentView = mLayoutInflater.inflate(R.layout.zen_mode_duration_dialog,
+                null);
+        ScrollView container = (ScrollView) contentView.findViewById(R.id.zen_duration_container);
+
+        mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
+        mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
+
+        for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
+            final View radioButton = mLayoutInflater.inflate(R.layout.zen_mode_radio_button,
+                    mZenRadioGroup, false);
+            mZenRadioGroup.addView(radioButton);
+            radioButton.setId(i);
+
+            final View radioButtonContent = mLayoutInflater.inflate(R.layout.zen_mode_condition,
+                    mZenRadioGroupContent, false);
+            radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
+            mZenRadioGroupContent.addView(radioButtonContent);
+        }
+
+        return contentView;
+    }
+
+    @VisibleForTesting
+    protected void setupRadioButtons(int zenDuration) {
+        int checkedIndex = ALWAYS_ASK_CONDITION_INDEX;
+        if (zenDuration == 0) {
+            checkedIndex = FOREVER_CONDITION_INDEX;
+        } else if (zenDuration > 0) {
+            checkedIndex = COUNTDOWN_CONDITION_INDEX;
+        }
+
+        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
+                FOREVER_CONDITION_INDEX);
+        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
+                COUNTDOWN_CONDITION_INDEX);
+        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(ALWAYS_ASK_CONDITION_INDEX),
+                ALWAYS_ASK_CONDITION_INDEX);
+        getConditionTagAt(checkedIndex).rb.setChecked(true);
+    }
+
+    private void bindTag(final int currZenDuration, final View row, final int rowIndex) {
+        final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
+                new ConditionTag();
+        row.setTag(tag);
+
+        if (tag.rb == null) {
+            tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowIndex);
+        }
+
+        // if duration is set to forever or always prompt, then countdown time defaults to 1 hour
+        if (currZenDuration <= 0) {
+            tag.countdownZenDuration = MINUTE_BUCKETS[DEFAULT_BUCKET_INDEX];
+        } else {
+            tag.countdownZenDuration = currZenDuration;
+        }
+
+        tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    tag.rb.setChecked(true);
+                }
+            }
+        });
+
+        updateUi(tag, row, rowIndex);
+    }
+
+    @VisibleForTesting
+    protected ConditionTag getConditionTagAt(int index) {
+        return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
+    }
+
+
+    private void setupUi(ConditionTag tag, View row) {
+        tag.lines = row.findViewById(android.R.id.content);
+        tag.line1 = (TextView) row.findViewById(android.R.id.text1);
+
+        // text2 is not used in zen duration dialog
+        row.findViewById(android.R.id.text2).setVisibility(View.GONE);
+
+        tag.lines.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                tag.rb.setChecked(true);
+            }
+        });
+    }
+
+    private void updateButtons(ConditionTag tag, View row, int rowIndex) {
+        // minus button
+        final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
+        button1.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onClickTimeButton(row, tag, false /*down*/, rowIndex);
+            }
+        });
+
+        // plus button
+        final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
+        button2.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onClickTimeButton(row, tag, true /*up*/, rowIndex);
+            }
+        });
+
+        final long time = tag.countdownZenDuration;
+        if (rowIndex == COUNTDOWN_CONDITION_INDEX) {
+            button1.setVisibility(View.VISIBLE);
+            button2.setVisibility(View.VISIBLE);
+
+            button1.setEnabled(time > MIN_BUCKET_MINUTES);
+            button2.setEnabled(tag.countdownZenDuration != MAX_BUCKET_MINUTES);
+
+            button1.setAlpha(button1.isEnabled() ? 1f : .5f);
+            button2.setAlpha(button2.isEnabled() ? 1f : .5f);
+        } else {
+            button1.setVisibility(View.GONE);
+            button2.setVisibility(View.GONE);
+        }
+    }
+
+    @VisibleForTesting
+    protected void updateUi(ConditionTag tag, View row, int rowIndex) {
+        if (tag.lines == null) {
+            setupUi(tag, row);
+        }
+
+        updateButtons(tag, row, rowIndex);
+
+        String radioContentText = "";
+        switch (rowIndex) {
+            case FOREVER_CONDITION_INDEX:
+                radioContentText = mContext.getString(
+                        com.android.internal.R.string.zen_mode_forever);
+                break;
+            case COUNTDOWN_CONDITION_INDEX:
+                Condition condition = ZenModeConfig.toTimeCondition(mContext,
+                        tag.countdownZenDuration, ActivityManager.getCurrentUser(), false);
+                radioContentText = condition.line1;
+                break;
+            case ALWAYS_ASK_CONDITION_INDEX:
+                radioContentText = mContext.getString(
+                        R.string.zen_mode_duration_always_prompt_title);
+                break;
+        }
+
+        tag.line1.setText(radioContentText);
+    }
+
+    @VisibleForTesting
+    protected void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
+        int newDndTimeDuration = -1;
+        final int N = MINUTE_BUCKETS.length;
+        if (mBucketIndex == -1) {
+            // not on a known index, search for the next or prev bucket by time
+            final long time = tag.countdownZenDuration;
+            for (int i = 0; i < N; i++) {
+                int j = up ? i : N - 1 - i;
+                final int bucketMinutes = MINUTE_BUCKETS[j];
+                if (up && bucketMinutes > time || !up && bucketMinutes < time) {
+                    mBucketIndex = j;
+                    newDndTimeDuration = bucketMinutes;
+                    break;
+                }
+            }
+            if (newDndTimeDuration == -1) {
+                mBucketIndex = DEFAULT_BUCKET_INDEX;
+                newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
+            }
+        } else {
+            // on a known index, simply increment or decrement
+            mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
+            newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
+        }
+        tag.countdownZenDuration = newDndTimeDuration;
+        bindTag(newDndTimeDuration, row, rowId);
+        tag.rb.setChecked(true);
+    }
+
+    // used as the view tag on condition rows
+    @VisibleForTesting
+    protected static class ConditionTag {
+        public RadioButton rb;
+        public View lines;
+        public TextView line1;
+        public int countdownZenDuration; // only important for countdown radio button
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 2482095..085e112 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -563,8 +563,7 @@
 
             // If there were no scan results, create an AP for the currently connected network (if
             // it exists).
-            // TODO(sghuman): Investigate if this works for an ephemeral (auto-connected) network
-            // when there are no scan results, as it may not have a valid WifiConfiguration
+            // TODO(b/b/73076869): Add support for passpoint (ephemeral) networks
             if (accessPoints.isEmpty() && connectionConfig != null) {
                 AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
                 activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 54c02a2..e435a72 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -18,9 +18,11 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -50,6 +52,7 @@
 import android.text.style.TtsSpan;
 
 import com.android.settingslib.R;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.settingslib.wifi.AccessPoint.Speed;
 
 import org.junit.Before;
@@ -61,6 +64,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -79,6 +83,8 @@
     private Context mContext;
     @Mock private RssiCurve mockBadgeCurve;
     @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache;
+    public static final int NETWORK_ID = 123;
+    public static final int DEFAULT_RSSI = -55;
 
     private static ScanResult createScanResult(String ssid, String bssid, int rssi) {
         ScanResult scanResult = new ScanResult();
@@ -753,16 +759,15 @@
         assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
     }
     @Test
-    public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() {
-        int networkId = 123;
-        int rssi = -55;
+    public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener()
+            throws InterruptedException {
         WifiConfiguration config = new WifiConfiguration();
-        config.networkId = networkId;
+        config.networkId = NETWORK_ID;
         config.numNoInternetAccessReports = 1;
 
         WifiInfo wifiInfo = new WifiInfo();
-        wifiInfo.setNetworkId(networkId);
-        wifiInfo.setRssi(rssi);
+        wifiInfo.setNetworkId(NETWORK_ID);
+        wifiInfo.setRssi(DEFAULT_RSSI);
 
         NetworkInfo networkInfo =
                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
@@ -770,8 +775,8 @@
 
         AccessPoint ap = new TestAccessPointBuilder(mContext)
                 .setNetworkInfo(networkInfo)
-                .setNetworkId(networkId)
-                .setRssi(rssi)
+                .setNetworkId(NETWORK_ID)
+                .setRssi(DEFAULT_RSSI)
                 .setWifiInfo(wifiInfo)
                 .build();
 
@@ -781,18 +786,131 @@
         config.validatedInternetAccess = true;
 
         assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse();
+
+        // Wait for MainHandler to process callback
+        CountDownLatch latch = new CountDownLatch(1);
+        ThreadUtils.postOnMainThread(latch::countDown);
+
+        latch.await();
         verify(mockListener).onAccessPointChanged(ap);
     }
 
     @Test
-    public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() {
-        int networkId = 123;
-        int rssi = -55;
+    public void testConnectionInfo_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
+            throws InterruptedException {
         WifiConfiguration config = new WifiConfiguration();
-        config.networkId = networkId;
+        config.networkId = NETWORK_ID;
+        config.numNoInternetAccessReports = 1;
+
         WifiInfo wifiInfo = new WifiInfo();
-        wifiInfo.setNetworkId(networkId);
-        wifiInfo.setRssi(rssi);
+        wifiInfo.setNetworkId(NETWORK_ID);
+        wifiInfo.setRssi(DEFAULT_RSSI);
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
+
+        AccessPoint ap = new TestAccessPointBuilder(mContext)
+                .setNetworkInfo(networkInfo)
+                .setNetworkId(NETWORK_ID)
+                .setRssi(DEFAULT_RSSI)
+                .setWifiInfo(wifiInfo)
+                .build();
+
+        WifiConfiguration newConfig = new WifiConfiguration(config);
+        config.validatedInternetAccess = true;
+
+        performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
+                ap, () -> assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse());
+
+    }
+
+    private void performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
+            AccessPoint ap, Runnable r) {
+        AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class);
+        ap.setListener(mockListener);
+
+        // Put a latch on the MainHandler to prevent the callback from being invoked instantly
+        CountDownLatch latch1 = new CountDownLatch(1);
+        ThreadUtils.postOnMainThread(() -> {
+            try{
+                latch1.await();
+            } catch (InterruptedException e) {
+                fail("Interruped Exception thrown while awaiting latch countdown");
+            }
+        });
+
+        r.run();
+
+        ap.setListener(null);
+        latch1.countDown();
+
+        // The second latch ensures the previously posted listener invocation has processed on the
+        // main thread.
+        CountDownLatch latch2 = new CountDownLatch(1);
+        ThreadUtils.postOnMainThread(latch2::countDown);
+
+        try{
+            latch2.await();
+        } catch (InterruptedException e) {
+            fail("Interruped Exception thrown while awaiting latch countdown");
+        }
+    }
+
+    @Test
+    public void testUpdateScanResults_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
+            throws InterruptedException {
+        String ssid = "ssid";
+        int newRssi = -80;
+        AccessPoint ap = new TestAccessPointBuilder(mContext).setSsid(ssid).build();
+
+        ScanResult scanResult = new ScanResult();
+        scanResult.SSID = ssid;
+        scanResult.level = newRssi;
+        scanResult.BSSID = "bssid";
+        scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
+        scanResult.capabilities = "";
+
+        performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
+                ap, () -> ap.setScanResults(Collections.singletonList(scanResult)));
+    }
+
+    @Test
+    public void testUpdateConfig_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution()
+            throws InterruptedException {
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = NETWORK_ID;
+        config.numNoInternetAccessReports = 1;
+
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setNetworkId(NETWORK_ID);
+        wifiInfo.setRssi(DEFAULT_RSSI);
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
+
+        AccessPoint ap = new TestAccessPointBuilder(mContext)
+                .setNetworkInfo(networkInfo)
+                .setNetworkId(NETWORK_ID)
+                .setRssi(DEFAULT_RSSI)
+                .setWifiInfo(wifiInfo)
+                .build();
+
+        WifiConfiguration newConfig = new WifiConfiguration(config);
+        config.validatedInternetAccess = true;
+
+        performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution(
+                ap, () -> ap.update(newConfig));
+    }
+
+    @Test
+    public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = NETWORK_ID;
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setNetworkId(NETWORK_ID);
+        wifiInfo.setRssi(DEFAULT_RSSI);
 
         NetworkInfo networkInfo =
                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
@@ -800,8 +918,8 @@
 
         AccessPoint ap = new TestAccessPointBuilder(mContext)
                 .setNetworkInfo(networkInfo)
-                .setNetworkId(networkId)
-                .setRssi(rssi)
+                .setNetworkId(NETWORK_ID)
+                .setRssi(DEFAULT_RSSI)
                 .setWifiInfo(wifiInfo)
                 .build();
 
@@ -847,34 +965,34 @@
                 .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2));
 
         ap.update(
-        mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS);
+            mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS);
 
         assertThat(ap.getSpeed()).isEqualTo(speed1);
     }
 
     @Test
     public void testSpeedLabelFallbackScoreIgnoresNullCurves() {
-        int rssi = -55;
         String bssid = "00:00:00:00:00:00";
-        int networkId = 123;
 
         WifiInfo info = new WifiInfo();
-        info.setRssi(rssi);
+        info.setRssi(DEFAULT_RSSI);
         info.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
         info.setBSSID(bssid);
-        info.setNetworkId(networkId);
+        info.setNetworkId(NETWORK_ID);
 
         ArrayList<ScanResult> scanResults = new ArrayList<>();
-        ScanResult scanResultUnconnected = createScanResult(TEST_SSID, "11:11:11:11:11:11", rssi);
+        ScanResult scanResultUnconnected =
+                createScanResult(TEST_SSID, "11:11:11:11:11:11", DEFAULT_RSSI);
         scanResults.add(scanResultUnconnected);
 
-        ScanResult scanResultConnected = createScanResult(TEST_SSID, bssid, rssi);
+        ScanResult scanResultConnected =
+                createScanResult(TEST_SSID, bssid, DEFAULT_RSSI);
         scanResults.add(scanResultConnected);
 
         AccessPoint ap =
                 new TestAccessPointBuilder(mContext)
                         .setActive(true)
-                        .setNetworkId(networkId)
+                        .setNetworkId(NETWORK_ID)
                         .setSsid(TEST_SSID)
                         .setScanResults(scanResults)
                         .setWifiInfo(info)
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index ca965f3..7fb4dc5 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -721,7 +721,7 @@
         // mStaleAccessPoints is true
         verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
 
-        assertThat(tracker.getAccessPoints().size()).isEqualTo(1);
+        assertThat(tracker.getAccessPoints()).hasSize(1);
         assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
new file mode 100644
index 0000000..9b491c2
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class ZenDurationDialogTest {
+    private ZenDurationDialog mController;
+
+    private Context mContext;
+    private LayoutInflater mLayoutInflater;
+    private Condition mCountdownCondition;
+    private Condition mAlarmCondition;
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setup() {
+        mContext = RuntimeEnvironment.application;
+        mContentResolver = RuntimeEnvironment.application.getContentResolver();
+        mLayoutInflater = LayoutInflater.from(mContext);
+
+        mController = spy(new ZenDurationDialog(mContext));
+        mController.mLayoutInflater = mLayoutInflater;
+        mController.getContentView();
+    }
+
+    @Test
+    public void testAlwaysPrompt() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_PROMPT);
+        mController.createDialog();
+
+        assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertTrue(mController.getConditionTagAt(
+                ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+    }
+
+    @Test
+    public void testForever() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_FOREVER);
+        mController.createDialog();
+
+        assertTrue(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(
+                ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+    }
+
+    @Test
+    public void testSpecificDuration() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION, 45);
+        mController.createDialog();
+
+        assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertTrue(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(
+                ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+    }
+
+
+    @Test
+    public void testChooseAlwaysPromptSetting() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_FOREVER);
+
+        AlertDialog dialog = (AlertDialog) mController.createDialog();
+        mController.getConditionTagAt(ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.setChecked(
+                true);
+        mController.updateZenDuration(Settings.Global.ZEN_DURATION_FOREVER);
+
+        assertEquals(Settings.Global.ZEN_DURATION_PROMPT, Settings.Global.getInt(mContentResolver,
+                Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_FOREVER));
+    }
+
+    @Test
+    public void testChooseForeverSetting() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_PROMPT);
+
+        AlertDialog dialog = (AlertDialog) mController.createDialog();
+        mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb.setChecked(
+                true);
+        mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
+
+        assertEquals(Settings.Global.ZEN_DURATION_FOREVER, Settings.Global.getInt(mContentResolver,
+                Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
+    }
+
+    @Test
+    public void testChooseTimeSetting() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_PROMPT);
+
+        AlertDialog dialog = (AlertDialog) mController.createDialog();
+        mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb.setChecked(
+                true);
+        mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
+
+        // countdown defaults to 60 minutes:
+        assertEquals(60, Settings.Global.getInt(mContentResolver,
+                Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
+    }
+
+    @Test
+    public void testGetTimeFromBucket() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_PROMPT);
+
+        AlertDialog dialog = (AlertDialog) mController.createDialog();
+        // click time button starts at 60 minutes
+        // - 1 hour to MAX_BUCKET_MINUTES (12 hours), increments by 1 hour
+        // - 0-60 minutes increments by 15 minutes
+        View view = mController.mZenRadioGroupContent.getChildAt(
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        ZenDurationDialog.ConditionTag tag = mController.getConditionTagAt(
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+
+        // test incrementing up:
+        mController.onClickTimeButton(view, tag, true, ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(120, tag.countdownZenDuration); // goes from 1 hour to 2 hours
+
+        // try clicking up 50 times - should max out at ZenDurationDialog.MAX_BUCKET_MINUTES
+        for (int i = 0; i < 50; i++) {
+            mController.onClickTimeButton(view, tag, true,
+                    ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        }
+        assertEquals(ZenDurationDialog.MAX_BUCKET_MINUTES, tag.countdownZenDuration);
+
+        // reset, test incrementing down:
+        mController.mBucketIndex = -1; // reset current bucket index to reset countdownZenDuration
+        tag.countdownZenDuration = 60; // back to default
+        mController.onClickTimeButton(view, tag, false,
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(45, tag.countdownZenDuration); // goes from 60 minutes to 45 minutes
+
+        // try clicking down 50 times - should stop at MIN_BUCKET_MINUTES
+        for (int i = 0; i < 50; i++) {
+            mController.onClickTimeButton(view, tag, false,
+                    ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        }
+        assertEquals(ZenDurationDialog.MIN_BUCKET_MINUTES, tag.countdownZenDuration);
+
+        // reset countdownZenDuration to unbucketed number, should round change to nearest bucket
+        mController.mBucketIndex = -1;
+        tag.countdownZenDuration = 50;
+        mController.onClickTimeButton(view, tag, false,
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(45, tag.countdownZenDuration);
+
+        mController.mBucketIndex = -1;
+        tag.countdownZenDuration = 50;
+        mController.onClickTimeButton(view, tag, true,
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(60, tag.countdownZenDuration);
+
+        mController.mBucketIndex = -1;
+        tag.countdownZenDuration = 75;
+        mController.onClickTimeButton(view, tag, false,
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(60, tag.countdownZenDuration);
+
+        mController.mBucketIndex = -1;
+        tag.countdownZenDuration = 75;
+        mController.onClickTimeButton(view, tag, true,
+                ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+        assertEquals(120, tag.countdownZenDuration);
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c173225..1cd02f4 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -200,4 +200,11 @@
 
     <!-- Default for Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS -->
     <string name="def_backup_local_transport_parameters"></string>
+
+    <!-- Default for Settings.Global.ZEN_DURATION
+        If 0, turning on dnd manually will last indefinitely.
+        Else if non-negative, turning on dnd manually will last for this many minutes.
+        Else (if negative), turning on dnd manually will surface a dialog that prompts
+            user to specify a duration.-->
+    <integer name="def_zen_duration">0</integer>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 11c869f..ccb4d8c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1141,6 +1141,9 @@
         dumpSetting(s, p,
                 Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
                 GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.ZEN_DURATION,
+                GlobalSettingsProto.ZEN_DURATION);
 
         // Please insert new settings using the same order as in Settings.Global.
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index baf17cb..6398858 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2938,7 +2938,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 156;
+            private static final int SETTINGS_VERSION = 157;
 
             private final int mUserId;
 
@@ -3604,7 +3604,21 @@
                     currentVersion = 156;
                 }
 
+                if (currentVersion == 156) {
+                    // Version 156: Set a default value for zen duration
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    final Setting currentSetting = globalSettings.getSettingLocked(
+                            Global.ZEN_DURATION);
+                    if (currentSetting.isNull()) {
+                        String defaultZenDuration = Integer.toString(getContext()
+                                .getResources().getInteger(R.integer.def_zen_duration));
+                        globalSettings.insertSettingLocked(
+                                Global.ZEN_DURATION, defaultZenDuration,
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
 
+                    currentVersion = 157;
+                }
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
index 8d03ce7..622226f 100644
--- a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="@*android:color/material_grey_200" />
+    <solid android:color="?android:attr/panelColorBackground" />
     <corners
         android:bottomLeftRadius="@dimen/corner_size"
         android:topLeftRadius="0dp"
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index 478b656..bfabe52 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -39,23 +39,13 @@
             android:theme="@android:style/Theme"
             android:layout_alignParentTop="true"/>
 
-        <!-- This progress bar is the countdown timer. -->
-        <ProgressBar
-            android:id="@+id/countdown_progress"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/car_user_switcher_progress_bar_height"
-            style="@style/CarUserSwitcher.ProgressBar"
-            android:layout_marginTop="@dimen/car_user_switcher_progress_bar_margin_top"
-            android:layout_alignParentTop="true"/>
-
         <com.android.systemui.statusbar.car.UserGridView
             android:id="@+id/user_grid"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginLeft="@dimen/car_margin"
             android:layout_marginRight="@dimen/car_margin"
-            android:layout_marginBottom="@dimen/car_user_grid_margin_bottom"
-            android:layout_centerInParent="true" />
+            android:layout_centerInParent="true"/>
 
         <com.android.systemui.statusbar.car.PageIndicator
             android:id="@+id/user_switcher_page_indicator"
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index 7844cac..447970c 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -42,7 +42,6 @@
             android:layout_height="wrap_content"
             android:layout_marginLeft="@dimen/car_margin"
             android:layout_marginRight="@dimen/car_margin"
-            android:layout_marginBottom="@dimen/car_user_grid_margin_bottom"
             android:layout_above="@id/user_switcher_page_indicator" />
 
         <com.android.systemui.statusbar.car.PageIndicator
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/fingerprint_dialog.xml
index 1b47489..1bdaf6e 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -26,116 +26,138 @@
     <View
         android:id="@+id/space"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="0dp"
         android:layout_weight="1" />
 
     <LinearLayout
-        android:id="@+id/dialog"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:elevation="2dp"
-        android:background="@drawable/fingerprint_dialog_bg">
+        android:layout_height="wrap_content">
 
-        <TextView
-            android:id="@+id/title"
-            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="24dp"
-            android:layout_marginStart="24dp"
-            android:layout_marginTop="24dp"
-            android:gravity="@integer/fingerprint_dialog_text_gravity"
-            android:textSize="20sp"
-            android:maxLines="1"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:marqueeRepeatLimit="marquee_forever"
-            android:textColor="@color/fingerprint_dialog_text_dark_color"/>
-
-        <TextView
-            android:id="@+id/subtitle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:layout_marginStart="24dp"
-            android:layout_marginEnd="24dp"
-            android:gravity="@integer/fingerprint_dialog_text_gravity"
-            android:textSize="16sp"
-            android:maxLines="1"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:marqueeRepeatLimit="marquee_forever"
-            android:textColor="@color/fingerprint_dialog_text_dark_color"/>
-
-        <TextView
-            android:id="@+id/description"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="24dp"
-            android:layout_marginStart="24dp"
-            android:gravity="@integer/fingerprint_dialog_text_gravity"
-            android:paddingTop="8dp"
-            android:textSize="16sp"
-            android:maxLines="4"
-            android:textColor="@color/fingerprint_dialog_text_dark_color"/>
-
-        <ImageView
-            android:id="@+id/fingerprint_icon"
-            android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
-            android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
-            android:layout_gravity="center_horizontal"
-            android:layout_marginTop="48dp"
-            android:scaleType="fitXY"
-            android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
-
-        <TextView
-            android:id="@+id/error"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="24dp"
-            android:layout_marginStart="24dp"
-            android:paddingTop="16dp"
-            android:paddingBottom="24dp"
-            android:textSize="12sp"
-            android:gravity="center_horizontal"
-            android:accessibilityLiveRegion="polite"
-            android:text="@string/fingerprint_dialog_touch_sensor"
-            android:contentDescription="@string/accessibility_fingerprint_dialog_help_area"
-            android:textColor="@color/fingerprint_dialog_text_light_color"/>
+        <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
+         on horizontal/portrait orientation -->
+        <View
+            android:id="@+id/left_space"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"/>
 
         <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="72dip"
-            android:paddingTop="24dp"
-            android:layout_gravity="center_vertical"
-            style="?android:attr/buttonBarStyle"
-            android:orientation="horizontal"
-            android:measureWithLargestChild="true">
-            <Space android:id="@+id/leftSpacer"
-                android:layout_width="24dp"
-                android:layout_height="match_parent"
-                android:visibility="visible" />
-            <!-- Negative Button -->
-            <Button android:id="@+id/button2"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                android:layout_marginStart="-12dp"
-                android:gravity="start|center_vertical"
-                android:maxLines="2" />
-            <!-- Positive Button -->
-            <Button android:id="@+id/button1"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                android:layout_marginEnd="12dp"
-                android:maxLines="2" />
-            <Space android:id="@+id/rightSpacer"
-                android:layout_width="24dip"
-                android:layout_height="match_parent"
-                android:visibility="gone" />
+            android:id="@+id/dialog"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:elevation="2dp"
+            android:background="@drawable/fingerprint_dialog_bg">
+
+            <TextView
+                android:id="@+id/title"
+                android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="24dp"
+                android:layout_marginStart="24dp"
+                android:layout_marginTop="24dp"
+                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:textSize="20sp"
+                android:maxLines="1"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:marqueeRepeatLimit="marquee_forever"
+                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+
+            <TextView
+                android:id="@+id/subtitle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"
+                android:layout_marginStart="24dp"
+                android:layout_marginEnd="24dp"
+                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:textSize="16sp"
+                android:maxLines="1"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:marqueeRepeatLimit="marquee_forever"
+                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+
+            <TextView
+                android:id="@+id/description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="24dp"
+                android:layout_marginStart="24dp"
+                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:paddingTop="8dp"
+                android:textSize="16sp"
+                android:maxLines="4"
+                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+
+            <ImageView
+                android:id="@+id/fingerprint_icon"
+                android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
+                android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="48dp"
+                android:scaleType="fitXY"
+                android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
+
+            <TextView
+                android:id="@+id/error"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="24dp"
+                android:layout_marginStart="24dp"
+                android:paddingTop="16dp"
+                android:paddingBottom="24dp"
+                android:textSize="12sp"
+                android:gravity="center_horizontal"
+                android:accessibilityLiveRegion="polite"
+                android:text="@string/fingerprint_dialog_touch_sensor"
+                android:contentDescription="@string/accessibility_fingerprint_dialog_help_area"
+                android:textColor="@color/fingerprint_dialog_text_light_color"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="72dip"
+                android:paddingTop="24dp"
+                android:layout_gravity="center_vertical"
+                style="?android:attr/buttonBarStyle"
+                android:orientation="horizontal"
+                android:measureWithLargestChild="true">
+                <Space android:id="@+id/leftSpacer"
+                    android:layout_width="24dp"
+                    android:layout_height="match_parent"
+                    android:visibility="visible" />
+                <!-- Negative Button -->
+                <Button android:id="@+id/button2"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                    android:layout_marginStart="-12dp"
+                    android:gravity="start|center_vertical"
+                    android:maxLines="2" />
+                <!-- Positive Button -->
+                <Button android:id="@+id/button1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                    android:layout_marginEnd="12dp"
+                    android:maxLines="2" />
+                <Space android:id="@+id/rightSpacer"
+                    android:layout_width="24dip"
+                    android:layout_height="match_parent"
+                    android:visibility="gone" />
+            </LinearLayout>
         </LinearLayout>
+
+        <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
+         on horizontal/portrait orientation -->
+        <View
+            android:id="@+id/right_space"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+
     </LinearLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 0063f6a..0a3f4eb 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -73,17 +73,19 @@
                     <!-- volume rows added and removed here! :-) -->
             </LinearLayout>
             <FrameLayout
-                android:layout_height="wrap_content"
+                android:id="@+id/settings_container"
                 android:layout_width="match_parent"
+                android:layout_height="wrap_content"
                 android:background="@drawable/rounded_bg_bottom_background">
                 <com.android.keyguard.AlphaOptimizedImageButton
                     android:id="@+id/settings"
-                    android:src="@drawable/ic_settings"
+                    android:src="@drawable/ic_settings_16dp"
                     android:layout_width="@dimen/volume_dialog_tap_target_size"
                     android:layout_height="@dimen/volume_dialog_tap_target_size"
                     android:layout_gravity="center"
+                    android:contentDescription="@string/accessibility_volume_settings"
                     android:background="?android:selectableItemBackgroundBorderless"
-                    android:tint="#8A000000"
+                    android:tint="?android:attr/colorControlNormal"
                     android:soundEffectsEnabled="false" />
             </FrameLayout>
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index def6f6b..bcc3692 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -25,7 +25,6 @@
     <LinearLayout
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
-        android:layout_marginTop="@dimen/volume_dialog_slider_margin_top"
         android:gravity="center"
         android:layout_gravity="center"
         android:orientation="vertical" >
@@ -42,6 +41,8 @@
         <FrameLayout
             android:id="@+id/volume_row_slider_frame"
             android:layout_width="match_parent"
+            android:layout_marginTop="@dimen/volume_dialog_slider_margin_top"
+            android:layout_marginBottom="@dimen/volume_dialog_slider_margin_bottom"
             android:layoutDirection="rtl"
             android:layout_height="@dimen/volume_dialog_slider_height">
             <SeekBar
@@ -60,6 +61,7 @@
             android:layout_width="@dimen/volume_dialog_tap_target_size"
             android:layout_height="@dimen/volume_dialog_tap_target_size"
             android:background="?android:selectableItemBackgroundBorderless"
+            android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom"
             android:tint="@color/accent_tint_color_selector"
             android:soundEffectsEnabled="false" />
     </LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 52b053b..e30b86a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -270,7 +270,7 @@
 
     <dimen name="volume_dialog_panel_width">64dp</dimen>
 
-    <dimen name="volume_dialog_slider_height">101dp</dimen>
+    <dimen name="volume_dialog_slider_height">108dp</dimen>
 
     <dimen name="volume_dialog_row_height">252dp</dimen>
 
@@ -280,7 +280,13 @@
 
     <dimen name="volume_dialog_spacer">4dp</dimen>
 
-    <dimen name="volume_dialog_slider_margin_top">13dp</dimen>
+    <dimen name="volume_dialog_slider_margin_top">22dp</dimen>
+
+    <dimen name="volume_dialog_slider_margin_bottom">-2dp</dimen>
+
+    <dimen name="volume_dialog_row_margin_bottom">8dp</dimen>
+
+    <dimen name="volume_dialog_settings_icon_size">16dp</dimen>
 
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index f3c9f89..5679dd2 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -36,8 +36,6 @@
     <dimen name="car_page_indicator_dot_diameter">12dp</dimen>
     <dimen name="car_page_indicator_margin_bottom">24dp</dimen>
 
-    <dimen name="car_user_switcher_progress_bar_height">6dp</dimen>
-    <dimen name="car_user_switcher_progress_bar_margin_top">@dimen/status_bar_height</dimen>
     <dimen name="car_start_driving_corner_radius">16dp</dimen>
     <dimen name="car_start_driving_padding_side">30dp</dimen>
     <dimen name="car_start_driving_height">80dp</dimen>
@@ -57,7 +55,6 @@
     <dimen name="car_user_switcher_container_height">420dp</dimen>
     <!-- This must be the negative of car_user_switcher_container_height for the animation. -->
     <dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
-    <dimen name="car_user_grid_margin_bottom">28dp</dimen>
 
     <dimen name="car_body2_size">26sp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml
index f84dd4b..a462576 100644
--- a/packages/SystemUI/res/values/integers_car.xml
+++ b/packages/SystemUI/res/values/integers_car.xml
@@ -16,8 +16,5 @@
 -->
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <integer name="car_user_switcher_timeout_ms">15000</integer>
-    <!-- This values less than ProgressBar.PROGRESS_ANIM_DURATION for a smooth animation. -->
-    <integer name="car_user_switcher_anim_update_ms">60</integer>
     <integer name="car_user_switcher_anim_cascade_delay_ms">27</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b7c1c55..814b3ef 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -377,6 +377,9 @@
     <!-- Content description of the data connection type 3.5G. [CHAR LIMIT=NONE] -->
     <string name="data_connection_3_5g">3.5G</string>
 
+    <!-- Content description of the data connection type 3.5G+. [CHAR LIMIT=NONE] -->
+    <string name="data_connection_3_5g_plus">3.5G+</string>
+
     <!-- Content description of the data connection type 4G . [CHAR LIMIT=NONE] -->
     <string name="data_connection_4g">4G</string>
 
@@ -1271,6 +1274,9 @@
     <!-- Button label for ending zen mode in the volume dialog -->
     <string name="volume_zen_end_now">Turn off now</string>
 
+    <!-- Content description for accessibility (not shown on the screen): volume dialog settings button. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_volume_settings">Sound settings</string>
+
     <!-- Content description for accessibility (not shown on the screen): volume dialog expand button. [CHAR LIMIT=NONE] -->
     <string name="accessibility_volume_expand">Expand</string>
 
diff --git a/packages/SystemUI/res/values/styles_car.xml b/packages/SystemUI/res/values/styles_car.xml
index c66792c..2aaef86 100644
--- a/packages/SystemUI/res/values/styles_car.xml
+++ b/packages/SystemUI/res/values/styles_car.xml
@@ -16,14 +16,6 @@
 -->
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <style name="CarUserSwitcher.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
-        <item name="android:progressDrawable">@drawable/car_progress_bar</item>
-        <item name="android:min">0</item>
-        <item name="android:max">@integer/car_user_switcher_timeout_ms</item>
-        <item name="android:progress">0</item>
-        <item name="android:interpolator">@android:anim/linear_interpolator</item>
-    </style>
-
     <style name="CarUserSwitcher.StartDrivingButton" parent="@android:style/Widget.Material.Button">
         <item name="android:background">@drawable/car_round_button</item>
         <item name="android:textSize">@dimen/car_start_driving_text_size</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
index 3bc1d9a..14767f1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
@@ -103,12 +103,13 @@
         int userId = taskKey.userId;
         Bitmap tdIcon = desc.getInMemoryIcon();
         if (tdIcon != null) {
-            return createDrawableFromBitmap(tdIcon, userId);
+            return createDrawableFromBitmap(tdIcon, userId, desc);
         }
         if (desc.getIconResource() != 0) {
             // TODO: Use task context here
             try {
-                return createBadgedDrawable(mContext.getDrawable(desc.getIconResource()), userId);
+                return createBadgedDrawable(
+                        mContext.getDrawable(desc.getIconResource()), userId, desc);
             } catch (Resources.NotFoundException e) {
                 Log.e(TAG, "Could not find icon drawable from resource", e);
             }
@@ -117,13 +118,13 @@
         tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
                 desc.getIconFilename(), userId);
         if (tdIcon != null) {
-            return createDrawableFromBitmap(tdIcon, userId);
+            return createDrawableFromBitmap(tdIcon, userId, desc);
         }
 
         // Load the icon from the activity info and cache it
         ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
         if (activityInfo != null) {
-            Drawable icon = getBadgedActivityIcon(activityInfo, userId);
+            Drawable icon = getBadgedActivityIcon(activityInfo, userId, desc);
             if (icon != null) {
                 return icon;
             }
@@ -135,16 +136,20 @@
 
     public abstract Drawable getDefaultIcon(int userId);
 
-    protected Drawable createDrawableFromBitmap(Bitmap icon, int userId) {
-        return createBadgedDrawable(new BitmapDrawable(mContext.getResources(), icon), userId);
+    protected Drawable createDrawableFromBitmap(Bitmap icon, int userId,
+            ActivityManager.TaskDescription desc) {
+        return createBadgedDrawable(
+                new BitmapDrawable(mContext.getResources(), icon), userId, desc);
     }
 
-    protected abstract Drawable createBadgedDrawable(Drawable icon, int userId);
+    protected abstract Drawable createBadgedDrawable(Drawable icon, int userId,
+            ActivityManager.TaskDescription desc);
 
     /**
      * @return the activity icon for the ActivityInfo for a user, badging if necessary.
      */
-    protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId);
+    protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId,
+            ActivityManager.TaskDescription desc);
 
     public static class DefaultIconLoader extends IconLoader {
 
@@ -168,7 +173,8 @@
         }
 
         @Override
-        protected Drawable createBadgedDrawable(Drawable icon, int userId) {
+        protected Drawable createBadgedDrawable(Drawable icon, int userId,
+                ActivityManager.TaskDescription desc) {
             if (userId != UserHandle.myUserId()) {
                 icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(userId));
             }
@@ -176,7 +182,8 @@
         }
 
         @Override
-        protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
+        protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId,
+                ActivityManager.TaskDescription desc) {
             return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
         }
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index dd1763b..924e85d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -31,6 +31,7 @@
     public int orientation;
     public Rect insets;
     public boolean reducedResolution;
+    public boolean isRealSnapshot;
     public float scale;
 
     public ThumbnailData() {
@@ -39,6 +40,7 @@
         insets = new Rect();
         reducedResolution = false;
         scale = 1f;
+        isRealSnapshot = true;
     }
 
     public ThumbnailData(TaskSnapshot snapshot) {
@@ -47,5 +49,6 @@
         orientation = snapshot.getOrientation();
         reducedResolution = snapshot.isReducedResolution();
         scale = snapshot.getScale();
+        isRealSnapshot = snapshot.isRealSnapshot();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index cad155c..5fce0a6 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -45,6 +45,7 @@
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.statusbar.AppOpsListener;
+import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -317,6 +318,8 @@
 
         mProviders.put(AppOpsListener.class, () -> new AppOpsListener(mContext));
 
+        mProviders.put(VibratorHelper.class, () -> new VibratorHelper(mContext));
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 903f3aa..ec2390f 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -31,6 +31,7 @@
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.provider.Settings.Secure;
 import android.support.annotation.VisibleForTesting;
@@ -312,6 +313,7 @@
 
         private final DisplayInfo mInfo = new DisplayInfo();
         private final Paint mPaint = new Paint();
+        private final Region mBounds = new Region();
         private final Rect mBoundingRect = new Rect();
         private final Path mBoundingPath = new Path();
         private final int[] mLocation = new int[2];
@@ -370,11 +372,13 @@
         private void update() {
             requestLayout();
             getDisplay().getDisplayInfo(mInfo);
+            mBounds.setEmpty();
             mBoundingRect.setEmpty();
             mBoundingPath.reset();
             int newVisible;
             if (hasCutout()) {
-                mBoundingRect.set(mInfo.displayCutout.getBoundingRect());
+                mBounds.set(mInfo.displayCutout.getBounds());
+                localBounds(mBoundingRect);
                 mInfo.displayCutout.getBounds().getBoundaryPath(mBoundingPath);
                 newVisible = VISIBLE;
             } else {
@@ -402,7 +406,7 @@
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            if (mBoundingRect.isEmpty()) {
+            if (mBounds.isEmpty()) {
                 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                 return;
             }
@@ -410,5 +414,50 @@
                     resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
                     resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
         }
+
+        public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, Rect out) {
+            Region bounds = displayCutout.getBounds();
+            switch (gravity) {
+                case Gravity.TOP:
+                    bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(),
+                            Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.LEFT:
+                    bounds.op(0, 0, displayCutout.getSafeInsetLeft(), Integer.MAX_VALUE,
+                            Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.BOTTOM:
+                    bounds.op(0, displayCutout.getSafeInsetTop() + 1, Integer.MAX_VALUE,
+                            Integer.MAX_VALUE, Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.RIGHT:
+                    bounds.op(displayCutout.getSafeInsetLeft() + 1, 0, Integer.MAX_VALUE,
+                            Integer.MAX_VALUE, Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+            }
+            bounds.recycle();
+        }
+
+        private void localBounds(Rect out) {
+            final DisplayCutout displayCutout = mInfo.displayCutout;
+
+            if (mStart) {
+                if (displayCutout.getSafeInsetLeft() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.LEFT, out);
+                } else if (displayCutout.getSafeInsetTop() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.TOP, out);
+                }
+            } else {
+                if (displayCutout.getSafeInsetRight() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.RIGHT, out);
+                } else if (displayCutout.getSafeInsetBottom() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.BOTTOM, out);
+                }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 37e1936..ebdc703 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.fingerprint;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
@@ -27,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -42,6 +44,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
 
 /**
  * This class loads the view for the system-provided dialog. The view consists of:
@@ -74,6 +77,8 @@
     private final LinearLayout mDialog;
     private int mLastState;
 
+    private final float mDisplayWidth;
+
     public FingerprintDialogView(Context context, Handler handler) {
         super(context);
         mHandler = handler;
@@ -88,6 +93,10 @@
         mFingerprintColor = Color.parseColor(
                 getResources().getString(R.color.fingerprint_dialog_fingerprint_color));
 
+        DisplayMetrics metrics = new DisplayMetrics();
+        mWindowManager.getDefaultDisplay().getMetrics(metrics);
+        mDisplayWidth = metrics.widthPixels;
+
         // Create the dialog
         LayoutInflater factory = LayoutInflater.from(getContext());
         mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
@@ -117,15 +126,14 @@
         });
 
         final View space = mLayout.findViewById(R.id.space);
+        final View leftSpace = mLayout.findViewById(R.id.left_space);
+        final View rightSpace = mLayout.findViewById(R.id.right_space);
         final Button negative = mLayout.findViewById(R.id.button2);
         final Button positive = mLayout.findViewById(R.id.button1);
 
-        space.setClickable(true);
-        space.setOnTouchListener((View view, MotionEvent event) -> {
-            mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled */)
-                    .sendToTarget();
-            return true;
-        });
+        setDismissesDialog(space);
+        setDismissesDialog(leftSpace);
+        setDismissesDialog(rightSpace);
 
         negative.setOnClickListener((View v) -> {
             mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_NEGATIVE).sendToTarget();
@@ -149,6 +157,8 @@
         final Button negative = mLayout.findViewById(R.id.button2);
         final Button positive = mLayout.findViewById(R.id.button1);
 
+        mDialog.getLayoutParams().width = (int) mDisplayWidth;
+
         mLastState = STATE_NONE;
         updateFingerprintIcon(STATE_FINGERPRINT);
 
@@ -189,6 +199,15 @@
         });
     }
 
+    private void setDismissesDialog(View v) {
+        v.setClickable(true);
+        v.setOnTouchListener((View view, MotionEvent event) -> {
+            mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled */)
+                    .sendToTarget();
+            return true;
+        });
+    }
+
     public void startDismiss() {
         final Runnable endActionRunnable = new Runnable() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 2d31669..f3a2ae3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,6 +19,7 @@
 import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
+import android.app.ActivityManager;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -139,15 +141,29 @@
 
     @Override
     public void showDetail(boolean show) {
-        mUiHandler.post(() -> {
-            Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
-            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            SystemUIDialog.setShowForAllUsers(mDialog, true);
-            SystemUIDialog.registerDismissListener(mDialog);
-            SystemUIDialog.setWindowOnTop(mDialog);
-            mUiHandler.post(() -> mDialog.show());
-            mHost.collapsePanels();
-        });
+        int zenDuration = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ZEN_DURATION, 0);
+        switch (zenDuration) {
+            case Settings.Global.ZEN_DURATION_PROMPT:
+                mUiHandler.post(() -> {
+                    Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
+                    mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+                    SystemUIDialog.setShowForAllUsers(mDialog, true);
+                    SystemUIDialog.registerDismissListener(mDialog);
+                    SystemUIDialog.setWindowOnTop(mDialog);
+                    mUiHandler.post(() -> mDialog.show());
+                    mHost.collapsePanels();
+                });
+                break;
+            case Settings.Global.ZEN_DURATION_FOREVER:
+                mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
+                break;
+            default:
+                Uri conditionId = ZenModeConfig.toTimeCondition(mContext, zenDuration,
+                        ActivityManager.getCurrentUser(), true).id;
+                mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+                        conditionId, TAG);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 3ec8913..bc353f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -19,7 +19,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.res.Resources;
-import android.os.CountDownTimer;
 import android.view.View;
 import android.view.ViewStub;
 import android.widget.ProgressBar;
@@ -36,16 +35,11 @@
     private final View mParent;
     private final UserGridView mUserGridView;
     private final UserSwitcherController mUserSwitcherController;
-    private final ProgressBar mProgressBar;
     private final ProgressBar mSwitchingUsers;
-    private final int mLoginTimeoutMs;
-    private final int mAnimUpdateIntervalMs;
     private final int mShortAnimDuration;
 
     private boolean mShowing;
 
-    private CountDownTimer mTimer;
-
     public FullscreenUserSwitcher(StatusBar statusBar,
             UserSwitcherController userSwitcherController,
             ViewStub containerStub) {
@@ -63,26 +57,13 @@
         PageIndicator pageIndicator = mContainer.findViewById(R.id.user_switcher_page_indicator);
         pageIndicator.setupWithViewPager(mUserGridView);
 
-        mProgressBar = mContainer.findViewById(R.id.countdown_progress);
         Resources res = mContainer.getResources();
-        mLoginTimeoutMs = res.getInteger(R.integer.car_user_switcher_timeout_ms);
-        mAnimUpdateIntervalMs = res.getInteger(R.integer.car_user_switcher_anim_update_ms);
         mShortAnimDuration = res.getInteger(android.R.integer.config_shortAnimTime);
 
         mContainer.findViewById(R.id.start_driving).setOnClickListener(v -> {
-            cancelTimer();
             automaticallySelectUser();
         });
 
-        // Any interaction with the screen should cancel the timer.
-        mContainer.setOnClickListener(v -> {
-            cancelTimer();
-        });
-        mUserGridView.setOnTouchListener((v, e) -> {
-            cancelTimer();
-            return false;
-        });
-
         mSwitchingUsers = mParent.findViewById(R.id.switching_users);
     }
 
@@ -127,44 +108,14 @@
         }
         mShowing = true;
         mParent.setVisibility(View.VISIBLE);
-        cancelTimer();
-
-        // This would be the case if we were in the middle of a switch.
-        if (mProgressBar.getVisibility() != View.VISIBLE) {
-            return;
-        }
-
-        mTimer = new CountDownTimer(mLoginTimeoutMs, mAnimUpdateIntervalMs) {
-            @Override
-            public void onTick(long msUntilFinished) {
-                int elapsed = mLoginTimeoutMs - (int) msUntilFinished;
-                mProgressBar.setProgress((int) elapsed, true /* animate */);
-            }
-
-            @Override
-            public void onFinish() {
-                mProgressBar.setProgress(mLoginTimeoutMs, true /* animate */);
-                automaticallySelectUser();
-            }
-        };
-        mTimer.start();
     }
 
     public void hide() {
         mShowing = false;
-        cancelTimer();
         toggleSwitchInProgress(false);
         mParent.setVisibility(View.GONE);
     }
 
-    private void cancelTimer() {
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer = null;
-            mProgressBar.setProgress(0, true /* animate */);
-        }
-    }
-
     private void automaticallySelectUser() {
         // TODO: Switch according to some policy. This implementation just tries to drop the
         //       keyguard for the current user.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index ca66e98..0716b37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -55,6 +55,7 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
@@ -912,4 +913,16 @@
             return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
         }
     }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        int bottom = insets.getDisplayCutout() != null
+                ? insets.getDisplayCutout().getSafeInsetBottom() : 0;
+        if (isPaddingRelative()) {
+            setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
+        } else {
+            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
+        }
+        return insets;
+    }
 }
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 1361cc4..bb929dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+
 import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -26,6 +28,7 @@
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.DisplayCutout;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -40,6 +43,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.ScreenDecorations;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -258,10 +262,13 @@
             updateLayoutParamsNoCutout();
         }
 
+        Rect bounds = new Rect();
+        boundsFromDirection(dc, Gravity.TOP, bounds);
+
         mCutoutSpace.setVisibility(View.VISIBLE);
         RelativeLayout.LayoutParams lp = (LayoutParams) mCutoutSpace.getLayoutParams();
-        lp.width = dc.getBoundingRect().width();
-        lp.height = dc.getBoundingRect().height();
+        lp.width = bounds.width();
+        lp.height = bounds.height();
         lp.addRule(RelativeLayout.CENTER_IN_PARENT);
 
         lp = (LayoutParams) mCarrierLabel.getLayoutParams();
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 ca5a350..e97fa85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -50,6 +50,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
@@ -246,7 +247,7 @@
 
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
-        mVibratorHelper = new VibratorHelper(context);
+        mVibratorHelper = Dependency.get(VibratorHelper.class);
 
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -1035,6 +1036,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+        requestApplyInsets();
         reorient();
         onPluginDisconnected(null); // Create default gesture helper
         Dependency.get(PluginManager.class).addPluginListener(this,
@@ -1112,6 +1114,13 @@
         pw.println("    }");
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+                insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+        return super.onApplyWindowInsets(insets);
+    }
+
     private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
         pw.print("      " + caption + ": ");
         if (button == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 3de0a41..7f1e9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -38,6 +38,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
@@ -207,7 +208,7 @@
         mFalsingManager = FalsingManager.getInstance(context);
         mNotificationsDragEnabled =
                 getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
-        mVibratorHelper = new VibratorHelper(context);
+        mVibratorHelper = Dependency.get(VibratorHelper.class);
         mVibrateOnOpening = mContext.getResources().getBoolean(
                 R.bool.config_vibrateOnIconAnimation);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index cf5c1c0..5076404 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -18,6 +18,8 @@
 
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
+import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -25,6 +27,7 @@
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.view.DisplayCutout;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -299,8 +302,12 @@
 
         mCutoutSpace.setVisibility(View.VISIBLE);
         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
-        lp.width = mDisplayCutout.getBoundingRect().width();
-        lp.height = mDisplayCutout.getBoundingRect().height();
+
+        Rect bounds = new Rect();
+        boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
+
+        lp.width = bounds.width();
+        lp.height = bounds.height();
     }
 
     private void updateSafeInsets() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 71376a5..f8b4e07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -126,6 +126,7 @@
     private float mExpansionFraction = 1f;
 
     private boolean mDarkenWhileDragging;
+    private boolean mExpansionAffectsAlpha = true;
     protected boolean mAnimateChange;
     private boolean mUpdatePending;
     private boolean mTracking;
@@ -381,6 +382,10 @@
     }
 
     private void applyExpansionToAlpha() {
+        if (!mExpansionAffectsAlpha) {
+            return;
+        }
+
         if (mState == ScrimState.UNLOCKED) {
             // Darken scrim as you pull down the shade when unlocked
             float behindFraction = getInterpolatedFraction();
@@ -912,6 +917,10 @@
         mScreenOn = false;
     }
 
+    public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
+        mExpansionAffectsAlpha = expansionAffectsAlpha;
+    }
+
     public interface Callback {
         default void onStart() {
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1219ada..e4f142a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3688,6 +3688,7 @@
     public void finishKeyguardFadingAway() {
         mKeyguardFadingAway = false;
         mKeyguardMonitor.notifyKeyguardDoneFading();
+        mScrimController.setExpansionAffectsAlpha(true);
     }
 
     // TODO: Move this to NotificationLockscreenUserManager.
@@ -4618,6 +4619,10 @@
         final boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
                 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
 
+        // Do not animate the scrim expansion when it's triggered by the fingerprint sensor.
+        mScrimController.setExpansionAffectsAlpha(mFingerprintUnlockController.getMode()
+                != FingerprintUnlockController.MODE_UNLOCK);
+
         if (mBouncerShowing) {
             final boolean qsExpanded = mQSPanel != null && mQSPanel.isExpanded();
             mScrimController.transitionTo(mIsOccluded || qsExpanded ?
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 81641da..3bcfd4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -126,7 +126,7 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         mRipple = new KeyButtonRipple(context, this);
-        mVibratorHelper = new VibratorHelper(context);
+        mVibratorHelper = Dependency.get(VibratorHelper.class);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         setBackground(mRipple);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 487d1c5..a046675 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -205,13 +205,15 @@
         }
 
         MobileIconGroup hGroup = TelephonyIcons.THREE_G;
+        MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
         if (mConfig.hspaDataDistinguishable) {
             hGroup = TelephonyIcons.H;
+            hPlusGroup = TelephonyIcons.H_PLUS;
         }
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
 
         if (mConfig.show4gForLte) {
             mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 5363742..2258fa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -884,6 +884,7 @@
                             datatype.equals("e") ? TelephonyIcons.E :
                             datatype.equals("g") ? TelephonyIcons.G :
                             datatype.equals("h") ? TelephonyIcons.H :
+                            datatype.equals("h+") ? TelephonyIcons.H_PLUS :
                             datatype.equals("lte") ? TelephonyIcons.LTE :
                             datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
                             datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 986abef..7e6fe02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -28,7 +28,6 @@
     static final int ICON_G = R.drawable.ic_g_mobiledata;
     static final int ICON_E = R.drawable.ic_e_mobiledata;
     static final int ICON_H = R.drawable.ic_h_mobiledata;
-    // TODO: add logic to insert H+ icon
     static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata;
     static final int ICON_3G = R.drawable.ic_3g_mobiledata;
     static final int ICON_4G = R.drawable.ic_4g_mobiledata;
@@ -135,6 +134,19 @@
             TelephonyIcons.ICON_H,
             false);
 
+    static final MobileIconGroup H_PLUS = new MobileIconGroup(
+            "H+",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.data_connection_3_5g_plus,
+            TelephonyIcons.ICON_H_PLUS,
+            false);
+
     static final MobileIconGroup FOUR_G = new MobileIconGroup(
             "4G",
             null,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index fe21f87..22bf983 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -23,6 +23,8 @@
 import static android.media.AudioManager.RINGER_MODE_SILENT;
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
 import static android.media.AudioManager.STREAM_ACCESSIBILITY;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
@@ -81,6 +83,7 @@
 import com.android.systemui.plugins.VolumeDialogController.State;
 import com.android.systemui.plugins.VolumeDialogController.StreamState;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -102,6 +105,7 @@
     private final Context mContext;
     private final H mHandler = new H();
     private final VolumeDialogController mController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
 
     private Window mWindow;
     private CustomDialog mDialog;
@@ -109,6 +113,7 @@
     private ViewGroup mDialogRowsView;
     private ViewGroup mRinger;
     private ImageButton mRingerIcon;
+    private View mSettingsView;
     private ImageButton mSettingsIcon;
     private ImageView mZenIcon;
     private final List<VolumeRow> mRows = new ArrayList<>();
@@ -139,6 +144,7 @@
         mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
         mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
     }
 
     public void init(int windowType, Callback callback) {
@@ -212,6 +218,7 @@
         mRinger = mDialog.findViewById(R.id.ringer);
         mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
         mZenIcon = mRinger.findViewById(R.id.dnd_icon);
+        mSettingsView = mDialog.findViewById(R.id.settings_container);
         mSettingsIcon = mDialog.findViewById(R.id.settings);
 
         if (mRows.isEmpty()) {
@@ -387,6 +394,8 @@
     }
 
     public void initSettingsH() {
+        mSettingsView.setVisibility(
+                mDeviceProvisionedController.isDeviceProvisioned() ? VISIBLE : GONE);
         mSettingsIcon.setOnClickListener(v -> {
             Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -607,7 +616,7 @@
      * @param enable whether to enable volume row views and hide dnd icon
      */
     private void enableVolumeRowViewsH(VolumeRow row, boolean enable) {
-        row.dndIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+        row.dndIcon.setVisibility(enable ? GONE : VISIBLE);
     }
 
     /**
@@ -617,7 +626,7 @@
      */
     private void enableRingerViewsH(boolean enable) {
         mRingerIcon.setEnabled(enable);
-        mZenIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+        mZenIcon.setVisibility(enable ? GONE : VISIBLE);
     }
 
     private void trimObsoleteH() {
@@ -797,7 +806,7 @@
         }
         final int progress = row.slider.getProgress();
         final int level = getImpliedLevel(row.slider, progress);
-        final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
+        final boolean rowVisible = row.view.getVisibility() == VISIBLE;
         final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
                 < USER_ATTEMPT_GRACE_PERIOD;
         mHandler.removeMessages(H.RECHECK, row);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index bfa469e..6fbc0d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -206,6 +206,25 @@
     }
 
     @Test
+    public void panelExpansionAffectsAlpha() {
+        mScrimController.setPanelExpansion(0f);
+        mScrimController.setPanelExpansion(0.5f);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        mScrimController.finishAnimationsImmediately();
+
+        final float scrimAlpha = mScrimBehind.getViewAlpha();
+        mScrimController.setExpansionAffectsAlpha(false);
+        mScrimController.setPanelExpansion(0.8f);
+        Assert.assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "
+                + "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
+
+        mScrimController.setExpansionAffectsAlpha(true);
+        mScrimController.setPanelExpansion(0.1f);
+        Assert.assertNotEquals("Scrim opacity should change when setExpansionAffectsAlpha "
+                + "is true", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
+    }
+
+    @Test
     public void transitionToUnlockedFromAod() {
         // Simulate unlock with fingerprint
         mScrimController.transitionTo(ScrimState.AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 8629799..365a9b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -74,6 +74,17 @@
         verifyDataIndicators(TelephonyIcons.ICON_H);
     }
 
+
+    @Test
+    public void testHspaPlusDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_HSPAP);
+
+        verifyDataIndicators(TelephonyIcons.ICON_H_PLUS);
+    }
+
+
     @Test
     public void testWfcNoDataIcon() {
         setupDefaultSignal();
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
new file mode 100644
index 0000000..d83b30a
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := DisplayCutoutEmulationDouble
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := DisplayCutoutEmulationDoubleOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..5d3385d
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.display.cutout.emulation.double"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <overlay android:targetPackage="android"
+        android:category="com.android.internal.display_cutout_emulation"
+        android:priority="1"/>
+
+    <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
new file mode 100644
index 0000000..ca261f9
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
@@ -0,0 +1,67 @@
+<!--
+  ~ 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">
+
+    <!-- The bounding path of the cutout region of the main built-in display.
+         Must either be empty if there is no cutout region, or a string that is parsable by
+         {@link android.util.PathParser}.
+
+         The path is assumed to be specified in display coordinates with pixel units and in
+         the display's native orientation, with the origin of the coordinate system at the
+         center top of the display.
+
+         To facilitate writing device-independent emulation overlays, the marker `@dp` can be
+         appended after the path string to interpret coordinates in dp instead of px units.
+         Note that a physical cutout should be configured in pixels for the best results.
+         -->
+    <string translatable="false" name="config_mainBuiltInDisplayCutout">
+        M 0,0
+        L -72, 0
+        L -69.9940446283, 20.0595537175
+        C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0
+        L 56.8, 32.0
+        C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175
+        L 72, 0
+        Z
+        @bottom
+        M 0,0
+        L -72, 0
+        L -69.9940446283, -20.0595537175
+        C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0
+        L 56.8, -32.0
+        C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20.0595537175
+        L 72, 0
+        Z
+        @dp
+    </string>
+
+    <!-- Whether the display cutout region of the main built-in display should be forced to
+         black in software (to avoid aliasing or emulate a cutout that is not physically existent).
+     -->
+    <bool name="config_fillMainBuiltInDisplayCutout">true</bool>
+
+    <!-- Height of the status bar -->
+    <dimen name="status_bar_height_portrait">48dp</dimen>
+    <dimen name="status_bar_height_landscape">28dp</dimen>
+    <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
+    <dimen name="quick_qs_offset_height">48dp</dimen>
+    <!-- Total height of QQS (quick_qs_offset_height + 128) -->
+    <dimen name="quick_qs_total_height">176dp</dimen>
+
+</resources>
+
+
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
new file mode 100644
index 0000000..68c2dcb
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/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">
+
+    <string name="display_cutout_emulation_overlay">Double display cutout</string>
+
+</resources>
+
diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
index ddac106..41a2940 100644
--- a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
+++ b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
@@ -7,5 +7,6 @@
         <item name="android:colorAccent">@*android:color/accent_device_default_dark</item>
         <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
         <item name="android:colorBackgroundFloating">@*android:color/material_grey_900</item>
+        <item name="android:panelColorBackground">@*android:color/material_grey_800</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 4be7287..d89cc96 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5363,7 +5363,6 @@
     // OS: P
     ACTION_PANEL_VIEW_EXPAND = 1328;
 
-
     // FIELD: Rotation of the device
     // CATEGORY: GLOBAL_SYSTEM_UI
     // OS: P
@@ -5500,6 +5499,10 @@
     // OS: P
     SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
 
+    // Action: notification shade > manage notifications
+    // OS: P
+    ACTION_MANAGE_NOTIFICATIONS = 1358;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index c9d5c27..490a59e 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -27,4 +27,5 @@
      int32 inset_top = 3;
      int32 inset_right = 4;
      int32 inset_bottom = 5;
+     bool is_real_snapshot = 6;
  }
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 8a66414..a5339e0 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -108,6 +108,10 @@
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
 
+    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
+    private static final List<String> DEFAULT_BUTTONS = Arrays.asList("url_bar",
+            "location_bar_edit_text");
+
     private final Context mContext;
     private final AutoFillUI mUi;
 
@@ -596,7 +600,7 @@
             final List<String> urlBarIds;
             if (urlBlockIndex == -1) {
                 packageName = packageBlock;
-                urlBarIds = null;
+                urlBarIds = DEFAULT_BUTTONS; // TODO(b/74445943): back to null
             } else {
                 if (packageBlock.charAt(packageBlock.length() - 1)
                         != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java
index 4bef81a..bd84782 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportStats.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java
@@ -32,9 +32,12 @@
 
     void registerConnectionTime(ComponentName transportComponent, long timeMs) {
         synchronized (mStatsLock) {
-            mTransportStats
-                    .computeIfAbsent(transportComponent, name -> new Stats())
-                    .register(timeMs);
+            Stats stats = mTransportStats.get(transportComponent);
+            if (stats == null) {
+                stats = new Stats();
+                mTransportStats.put(transportComponent, stats);
+            }
+            stats.register(timeMs);
         }
     }
 
@@ -71,52 +74,49 @@
     private static void dumpStats(PrintWriter pw, String prefix, Stats stats) {
         pw.println(
                 String.format(
-                        Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.mAverage));
-        pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.mMax));
-        pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.mMin));
-        pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.mN));
+                        Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.average));
+        pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.max));
+        pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.min));
+        pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.n));
     }
 
     public static final class Stats {
         public static Stats merge(Stats a, Stats b) {
             return new Stats(
-                    a.mN + b.mN,
-                    (a.mAverage * a.mN + b.mAverage * b.mN) / (a.mN + b.mN),
-                    Math.max(a.mMax, b.mMax),
-                    Math.min(a.mMin, b.mMin));
+                    a.n + b.n,
+                    (a.average * a.n + b.average * b.n) / (a.n + b.n),
+                    Math.max(a.max, b.max),
+                    Math.min(a.min, b.min));
         }
 
-        public int mN;
-        public double mAverage;
-        public long mMax;
-        public long mMin;
+        public int n;
+        public double average;
+        public long max;
+        public long min;
 
         public Stats() {
-            mN = 0;
-            mAverage = 0;
-            mMax = 0;
-            mMin = Long.MAX_VALUE;
-        }
-
-        private Stats(Stats original) {
-            mN = original.mN;
-            mAverage = original.mAverage;
-            mMax = original.mMax;
-            mMin = original.mMin;
+            n = 0;
+            average = 0;
+            max = 0;
+            min = Long.MAX_VALUE;
         }
 
         private Stats(int n, double average, long max, long min) {
-            mN = n;
-            mAverage = average;
-            mMax = max;
-            mMin = min;
+            this.n = n;
+            this.average = average;
+            this.max = max;
+            this.min = min;
+        }
+
+        private Stats(Stats original) {
+            this(original.n, original.average, original.max, original.min);
         }
 
         private void register(long sample) {
-            mAverage = (mAverage * mN + sample) / (mN + 1);
-            mN++;
-            mMax = Math.max(mMax, sample);
-            mMin = Math.min(mMin, sample);
+            average = (average * n + sample) / (n + 1);
+            n++;
+            max = Math.max(max, sample);
+            min = Math.min(min, sample);
         }
     }
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 3927ebd..62e82a0 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -394,8 +394,10 @@
                 + " callback.asBinder=" + callback.asBinder());
         }
 
+        // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, callingPackage, "addOnSubscriptionsChangedListener")) {
+                mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
+                "addOnSubscriptionsChangedListener")) {
             return;
         }
 
@@ -686,8 +688,9 @@
 
     private boolean canReadPhoneState(String callingPackage, String message) {
         try {
+            // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
             return TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                    mContext, callingPackage, message);
+                    mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
         } catch (SecurityException e) {
             return false;
         }
@@ -1735,8 +1738,9 @@
         }
 
         if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
-            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                    mContext, callingPackage, message)) {
+            // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
+            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext,
+                    SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message)) {
                 return false;
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c1c68e8..96633da 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5401,11 +5401,12 @@
 
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
+        final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
                 return mStackSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
-                        SafeActivityOptions.fromBundle(bOptions));
+                        safeOptions);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 59f027a..e38be67 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1750,8 +1750,11 @@
             // this when there is an activity waiting to become translucent as the extra binder
             // calls will lead to noticeable jank. A later call to
             // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper
-            // paused state.
-            if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null) {
+            // paused state. We also avoid doing this for the activity the stack supervisor
+            // considers the resumed activity, as normal means will bring the activity from STOPPED
+            // to RESUMED. Adding PAUSING in this scenario will lead to double lifecycles.
+            if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null
+                    && mStackSupervisor.getResumedActivityLocked() != this) {
                 // Capture reason before state change
                 final String reason = getLifecycleDescription("makeVisibleIfNeeded");
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 869c635..185897a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3375,11 +3375,11 @@
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
                     stack.awakeFromSleepingLocked();
-                    if (isFocusedStack(stack)
-                            && !mKeyguardController.isKeyguardActive(display.mDisplayId)) {
-                        // If there is no keyguard on this display - resume immediately. Otherwise
-                        // we'll wait for keyguard visibility callback and resume while ensuring
-                        // activities visibility
+                    if (isFocusedStack(stack) && !mKeyguardController.isKeyguardLocked()) {
+                        // If the keyguard is unlocked - resume immediately.
+                        // It is possible that the display will not be awake at the time we
+                        // process the keyguard going away, which can happen before the sleep token
+                        // is released. As a result, it is important we resume the activity here.
                         resumeFocusedStackTopActivityLocked();
                     }
                 }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 6b8b380..72882de 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -86,16 +86,8 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return isKeyguardActive(displayId) && !mKeyguardGoingAway;
-    }
-
-    /**
-     * @return true if Keyguard is showing and not occluded. We ignore whether it is going away or
-     *         not here.
-     */
-    boolean isKeyguardActive(int displayId) {
-        return mKeyguardShowing && (displayId == DEFAULT_DISPLAY ? !mOccluded
-                : displayId == mSecondaryDisplayShowing);
+        return mKeyguardShowing && !mKeyguardGoingAway &&
+                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index f1a806b..4f31e53 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -102,9 +102,12 @@
 
 
     /**
-     * There are only 2 possible callbacks.
+     * There are only 3 possible callbacks.
      *
-     * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY].
+     * mNetdEventCallbackList[CALLBACK_CALLER_CONNECTIVITY_SERVICE]
+     * Callback registered/unregistered by ConnectivityService.
+     *
+     * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY]
      * Callback registered/unregistered when logging is being enabled/disabled in DPM
      * by the device owner. It's DevicePolicyManager's responsibility to ensure that.
      *
@@ -113,6 +116,7 @@
      */
     @GuardedBy("this")
     private static final int[] ALLOWED_CALLBACK_TYPES = {
+        INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE,
         INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY,
         INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST
     };
@@ -212,6 +216,19 @@
     @Override
     // Called concurrently by multiple binder threads.
     // This method must not block or perform long-running operations.
+    public synchronized void onPrivateDnsValidationEvent(int netId,
+            String ipAddress, String hostname, boolean validated)
+            throws RemoteException {
+        for (INetdEventCallback callback : mNetdEventCallbackList) {
+            if (callback != null) {
+                callback.onPrivateDnsValidationEvent(netId, ipAddress, hostname, validated);
+            }
+        }
+    }
+
+    @Override
+    // Called concurrently by multiple binder threads.
+    // This method must not block or perform long-running operations.
     public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr,
             int port, int uid) throws RemoteException {
         long timestamp = System.currentTimeMillis();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b7385d8..0d8ec6d 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -404,7 +404,8 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
-                    mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width);
+                    mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width,
+                            mInfo.height);
                     mInfo.type = Display.TYPE_BUILT_IN;
                     mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
                     mInfo.xDpi = phys.xDpi;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index c3259c3..ac85484 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -26,8 +26,10 @@
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
+import android.app.IActivityManager;
 import android.app.PendingIntent;
 import android.app.SynchronousUserSwitchObserver;
+import android.app.TaskStackListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -137,6 +139,7 @@
     @GuardedBy("this")
     private IBiometricsFingerprint mDaemon;
     private IStatusBarService mStatusBarService;
+    private final IActivityManager mActivityManager;
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final UserManager mUserManager;
@@ -215,6 +218,30 @@
         }
     };
 
+    private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+        @Override
+        public void onTaskStackChanged() {
+            try {
+                if (!(mCurrentClient instanceof AuthenticationClient)) {
+                    return;
+                }
+                if (isKeyguard(mCurrentClient.getOwnerString())) {
+                    return; // Keyguard is always allowed
+                }
+                List<ActivityManager.RunningTaskInfo> runningTasks = mActivityManager.getTasks(1);
+                if (!runningTasks.isEmpty()) {
+                    if (runningTasks.get(0).topActivity.getPackageName()
+                            != mCurrentClient.getOwnerString()) {
+                        mCurrentClient.stop(false /* initiatedByClient */);
+                        Slog.e(TAG, "Stopping background authentication");
+                    }
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to get running tasks", e);
+            }
+        }
+    };
+
     public FingerprintService(Context context) {
         super(context);
         mContext = context;
@@ -230,6 +257,13 @@
         mFailedAttempts = new SparseIntArray();
         mStatusBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mActivityManager = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
+                .getService();
+        try {
+            mActivityManager.registerTaskStackListener(mTaskStackListener);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Could not register task stack listener", e);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b68b98d..b9fb2e0 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1782,11 +1782,10 @@
      * Report to usage stats that the notification was seen.
      * @param r notification record
      */
+    @GuardedBy("mNotificationLock")
     protected void reportSeen(NotificationRecord r) {
-        final int userId = r.sbn.getUserId();
         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                userId == UserHandle.USER_ALL ? USER_SYSTEM
-                        : userId,
+                getRealUserId(r.sbn.getUserId()),
                 UsageEvents.Event.NOTIFICATION_SEEN);
     }
 
@@ -1858,17 +1857,30 @@
         return newSuppressedVisualEffects;
     }
 
+    // TODO: log visual differences, not just audible ones
+    @GuardedBy("mNotificationLock")
+    protected void maybeRecordInterruptionLocked(NotificationRecord r) {
+        if (r.isInterruptive()) {
+            mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
+                    r.getChannel().getId(),
+                    getRealUserId(r.sbn.getUserId()));
+        }
+    }
+
     /**
      * Report to usage stats that the notification was clicked.
      * @param r notification record
      */
     protected void reportUserInteraction(NotificationRecord r) {
-        final int userId = r.sbn.getUserId();
         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
+                getRealUserId(r.sbn.getUserId()),
                 UsageEvents.Event.USER_INTERACTION);
     }
 
+    private int getRealUserId(int userId) {
+        return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
+    }
+
     @VisibleForTesting
     NotificationManagerInternal getInternalService() {
         return mInternalService;
@@ -4345,6 +4357,7 @@
                     }
 
                     buzzBeepBlinkLocked(r);
+                    maybeRecordInterruptionLocked(r);
                 } finally {
                     int N = mEnqueuedNotifications.size();
                     for (int i = 0; i < N; i++) {
@@ -4554,6 +4567,7 @@
             updateLightsLocked();
         }
         if (buzz || beep || blink) {
+            record.setInterruptive(true);
             MetricsLogger.action(record.getLogMaker()
                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                     .setType(MetricsEvent.TYPE_OPEN)
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4404c48..f1908bf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -145,6 +145,7 @@
     private final List<Adjustment> mAdjustments;
     private final NotificationStats mStats;
     private int mUserSentiment;
+    private boolean mIsInterruptive;
 
     @VisibleForTesting
     public NotificationRecord(Context context, StatusBarNotification sbn,
@@ -519,6 +520,7 @@
         pw.println(prefix + "mLight= " + mLight);
         pw.println(prefix + "mShowBadge=" + mShowBadge);
         pw.println(prefix + "mColorized=" + notification.isColorized());
+        pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
         pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
         if (getPeopleOverride() != null) {
             pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
@@ -888,6 +890,14 @@
         return mPeopleOverride;
     }
 
+    public void setInterruptive(boolean interruptive) {
+        mIsInterruptive = interruptive;
+    }
+
+    public boolean isInterruptive() {
+        return mIsInterruptive;
+    }
+
     protected void setPeopleOverride(ArrayList<String> people) {
         mPeopleOverride = people;
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87be0a2..2d4438d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2680,8 +2680,9 @@
                 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
                 break;
             case TYPE_DREAM:
-                // Dreams don't have an app window token and can thus not be letterboxed.
-                // Hence always let them extend under the cutout.
+            case TYPE_WALLPAPER:
+                // Dreams and wallpapers don't have an app window token and can thus not be
+                // letterboxed. Hence always let them extend under the cutout.
                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
                 break;
             case TYPE_STATUS_BAR:
@@ -4490,7 +4491,8 @@
                         displayWidth, displayHeight);
                 outFrame.intersect(taskBounds);
             }
-            outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame));
+            outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
+                    .getDisplayCutout());
             return mForceShowSystemBars;
         } else {
             if (layoutInScreen) {
@@ -4756,7 +4758,7 @@
             // It's a system nav bar or a portrait screen; nav bar goes on bottom.
             final int top = cutoutSafeUnrestricted.bottom
                     - getNavigationBarHeight(rotation, uiMode);
-            mTmpNavigationFrame.set(0, top, displayWidth, cutoutSafeUnrestricted.bottom);
+            mTmpNavigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom);
             displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4779,7 +4781,7 @@
             // Landscape screen; nav bar goes to the right.
             final int left = cutoutSafeUnrestricted.right
                     - getNavigationBarWidth(rotation, uiMode);
-            mTmpNavigationFrame.set(left, 0, cutoutSafeUnrestricted.right, displayHeight);
+            mTmpNavigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
             displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4802,7 +4804,7 @@
             // Seascape screen; nav bar goes to the left.
             final int right = cutoutSafeUnrestricted.left
                     + getNavigationBarWidth(rotation, uiMode);
-            mTmpNavigationFrame.set(cutoutSafeUnrestricted.left, 0, right, displayHeight);
+            mTmpNavigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
             displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4831,8 +4833,9 @@
         mStatusBarLayer = mNavigationBar.getSurfaceLayer();
         // And compute the final frame.
         mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
-                mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutout);
+                mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf,
+                mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe,
+                displayFrames.mDisplayCutout);
         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
         return mNavigationBarController.checkHiddenLw();
     }
@@ -4990,8 +4993,7 @@
             df.set(displayFrames.mDock);
             pf.set(displayFrames.mDock);
             // IM dock windows layout below the nav bar...
-            pf.bottom = df.bottom = of.bottom = Math.min(displayFrames.mUnrestricted.bottom,
-                    displayFrames.mDisplayCutoutSafe.bottom);
+            pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
             // ...with content insets above the nav bar
             cf.bottom = vf.bottom = displayFrames.mStable.bottom;
             if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
@@ -5292,27 +5294,48 @@
 
         final int cutoutMode = attrs.layoutInDisplayCutoutMode;
         final boolean attachedInParent = attached != null && !layoutInScreen;
+        final boolean requestedHideNavigation =
+                (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
         // the cutout safe zone.
         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
-            final Rect displayCutoutSafeExceptMaybeTop = mTmpRect;
-            displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe);
+            final Rect displayCutoutSafeExceptMaybeBars = mTmpRect;
+            displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
                 // At the top we have the status bar, so apps that are
                 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
                 // already expect that there's an inset there and we don't need to exclude
                 // the window from that area.
-                displayCutoutSafeExceptMaybeTop.top = Integer.MIN_VALUE;
+                displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
+            }
+            if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
+                    && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
+                // Same for the navigation bar.
+                switch (mNavigationBarPosition) {
+                    case NAV_BAR_BOTTOM:
+                        displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
+                        break;
+                    case NAV_BAR_RIGHT:
+                        displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
+                        break;
+                    case NAV_BAR_LEFT:
+                        displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
+                        break;
+                }
+            }
+            if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+                // The IME can always extend under the bottom cutout if the navbar is there.
+                displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
             }
             // Windows that are attached to a parent and laid out in said parent are already
             // avoidingthe cutout according to that parent and don't need to be further constrained.
             if (!attachedInParent) {
-                pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
+                pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
             }
-            // Make sure that NO_LIMITS windows clipped to the display don't extend into the display
-            // don't extend under the cutout.
-            df.intersectUnchecked(displayCutoutSafeExceptMaybeTop);
+            // Make sure that NO_LIMITS windows clipped to the display don't extend under the
+            // cutout.
+            df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
         }
 
         // Content should never appear in the cutout.
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 9bd508e..8ec8c5b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -93,6 +93,7 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.wm.DisplayFrames;
+import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -217,11 +218,11 @@
          * @param stableFrame The frame around which stable system decoration is positioned.
          * @param outsetFrame The frame that includes areas that aren't part of the surface but we
          * want to treat them as such.
-         * @param displayCutout the display displayCutout
+         * @param displayCutout the display cutout
          */
         public void computeFrameLw(Rect parentFrame, Rect displayFrame,
                 Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
-                Rect stableFrame, @Nullable Rect outsetFrame, DisplayCutout displayCutout);
+                Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout);
 
         /**
          * Retrieve the current frame of the window that has been assigned by
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 0ac853b..6053512 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -16,11 +16,12 @@
 
 package com.android.server.textclassifier;
 
-import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -30,6 +31,7 @@
 import android.service.textclassifier.ITextLinksCallback;
 import android.service.textclassifier.ITextSelectionCallback;
 import android.service.textclassifier.TextClassifierService;
+import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
@@ -216,6 +218,23 @@
         }
     }
 
+    @Override
+    public void onSelectionEvent(SelectionEvent event) throws RemoteException {
+        validateInput(event, mContext);
+
+        synchronized (mLock) {
+            if (isBoundLocked()) {
+                mService.onSelectionEvent(event);
+            } else {
+                final Callable<Void> request = () -> {
+                    onSelectionEvent(event);
+                    return null;
+                };
+                enqueueRequestLocked(request, null /* onServiceFailure */, null /* binder */);
+            }
+        }
+    }
+
     /**
      * @return true if the service is bound or in the process of being bound.
      *      Returns false otherwise.
@@ -281,8 +300,8 @@
     private final class PendingRequest implements IBinder.DeathRecipient {
 
         private final Callable<Void> mRequest;
-        private final Callable<Void> mOnServiceFailure;
-        private final IBinder mBinder;
+        @Nullable private final Callable<Void> mOnServiceFailure;
+        @Nullable private final IBinder mBinder;
 
         /**
          * Initializes a new pending request.
@@ -292,15 +311,17 @@
          * @param binder binder to the process that made this pending request
          */
         PendingRequest(
-                @NonNull Callable<Void> request, @NonNull Callable<Void> onServiceFailure,
-                @NonNull IBinder binder) {
+                Callable<Void> request, @Nullable Callable<Void> onServiceFailure,
+                @Nullable IBinder binder) {
             mRequest = Preconditions.checkNotNull(request);
-            mOnServiceFailure = Preconditions.checkNotNull(onServiceFailure);
-            mBinder = Preconditions.checkNotNull(binder);
-            try {
-                mBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                e.printStackTrace();
+            mOnServiceFailure = onServiceFailure;
+            mBinder = binder;
+            if (mBinder != null) {
+                try {
+                    mBinder.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
             }
         }
 
@@ -317,11 +338,13 @@
         @GuardedBy("mLock")
         void notifyServiceFailureLocked() {
             removeLocked();
-            try {
-                mOnServiceFailure.call();
-            } catch (Exception e) {
-                Slog.d(LOG_TAG, "Error notifying callback of service failure: "
-                        + e.getMessage());
+            if (mOnServiceFailure != null) {
+                try {
+                    mOnServiceFailure.call();
+                } catch (Exception e) {
+                    Slog.d(LOG_TAG, "Error notifying callback of service failure: "
+                            + e.getMessage());
+                }
             }
         }
 
@@ -336,7 +359,9 @@
         @GuardedBy("mLock")
         private void removeLocked() {
             mPendingRequests.remove(this);
-            mBinder.unlinkToDeath(this, 0);
+            if (mBinder != null) {
+                mBinder.unlinkToDeath(this, 0);
+            }
         }
     }
 
@@ -359,4 +384,16 @@
             throw new RemoteException(e.getMessage());
         }
     }
+
+    private static void validateInput(SelectionEvent event, Context context)
+            throws RemoteException {
+        try {
+            final int uid = context.getPackageManager()
+                    .getPackageUid(event.getPackageName(), 0);
+            Preconditions.checkArgument(Binder.getCallingUid() == uid);
+        } catch (IllegalArgumentException | NullPointerException |
+                PackageManager.NameNotFoundException e) {
+            throw new RemoteException(e.getMessage());
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 64f77a2..00e3050 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -17,13 +17,15 @@
 package com.android.server.wm;
 
 import android.annotation.ColorInt;
-import android.graphics.Point;
+import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.animation.Animation;
 
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
+import java.io.PrintWriter;
+
 /**
  * Interface that describes an animation and bridges the animation start to the component
  * responsible for running the animation.
@@ -83,4 +85,14 @@
      * @return the desired start time of the status bar transition, in uptime millis
      */
     long getStatusBarTransitionsStartTime();
+
+    void dump(PrintWriter pw, String prefix);
+
+    default void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        writeToProto(proto);
+        proto.end(token);
+    }
+
+    void writeToProto(ProtoOutputStream proto);
 }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index a180a3a..5c62987 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -16,11 +16,19 @@
 
 package com.android.server.wm;
 
-import android.view.SurfaceControl;
+import static com.android.server.wm.proto.AlphaAnimationSpecProto.DURATION;
+import static com.android.server.wm.proto.AlphaAnimationSpecProto.FROM;
+import static com.android.server.wm.proto.AlphaAnimationSpecProto.TO;
+import static com.android.server.wm.proto.AnimationSpecProto.ALPHA;
+
 import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
+import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.PrintWriter;
+
 /**
  * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is
  * black layers of varying opacity at various Z-levels which create the effect of a Dim.
@@ -334,5 +342,21 @@
                     + mFromAlpha;
             t.setAlpha(sc, alpha);
         }
+
+        @Override
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix); pw.print("from="); pw.print(mFromAlpha);
+            pw.print(" to="); pw.print(mToAlpha);
+            pw.print(" duration="); pw.println(mDuration);
+        }
+
+        @Override
+        public void writeToProtoInner(ProtoOutputStream proto) {
+            final long token = proto.start(ALPHA);
+            proto.write(FROM, mFromAlpha);
+            proto.write(TO, mToAlpha);
+            proto.write(DURATION, mDuration);
+            proto.end(token);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7b5e8b8..2dce913 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -154,6 +154,7 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.RotationCache;
+import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -214,7 +215,7 @@
     int mInitialDisplayDensity = 0;
 
     DisplayCutout mInitialDisplayCutout;
-    private final RotationCache<DisplayCutout, DisplayCutout> mDisplayCutoutCache
+    private final RotationCache<DisplayCutout, WmDisplayCutout> mDisplayCutoutCache
             = new RotationCache<>(this::calculateDisplayCutoutForRotationUncached);
 
     /**
@@ -735,7 +736,8 @@
         display.getDisplayInfo(mDisplayInfo);
         display.getMetrics(mDisplayMetrics);
         isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
-        mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo);
+        mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo,
+                calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
         initializeDisplayBaseInfo();
         mDividerControllerLocked = new DockedStackDividerController(service, this);
         mPinnedStackControllerLocked = new PinnedStackController(service, this);
@@ -1128,7 +1130,8 @@
         mService.mPolicy.setInitialDisplaySize(getDisplay(),
                 mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
 
-        mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo);
+        mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
+                calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
     }
 
     /**
@@ -1161,8 +1164,9 @@
         }
 
         // Update application display metrics.
-        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(
-                mRotation);
+        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
+        final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
+
         final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
                 mDisplayId, displayCutout);
         final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
@@ -1177,7 +1181,7 @@
             mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
         }
-        mDisplayInfo.displayCutout = displayCutout;
+        mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
         mDisplayInfo.getAppMetrics(mDisplayMetrics);
         if (mDisplayScalingDisabled) {
             mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -1199,24 +1203,25 @@
         return mDisplayInfo;
     }
 
-    DisplayCutout calculateDisplayCutoutForRotation(int rotation) {
+    WmDisplayCutout calculateDisplayCutoutForRotation(int rotation) {
         return mDisplayCutoutCache.getOrCompute(mInitialDisplayCutout, rotation);
     }
 
-    private DisplayCutout calculateDisplayCutoutForRotationUncached(
+    private WmDisplayCutout calculateDisplayCutoutForRotationUncached(
             DisplayCutout cutout, int rotation) {
         if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
-            return cutout;
+            return WmDisplayCutout.NO_CUTOUT;
         }
         if (rotation == ROTATION_0) {
-            return cutout.computeSafeInsets(mInitialDisplayWidth, mInitialDisplayHeight);
+            return WmDisplayCutout.computeSafeInsets(
+                    cutout, mInitialDisplayWidth, mInitialDisplayHeight);
         }
         final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
         final Path bounds = cutout.getBounds().getBoundaryPath();
         transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight,
                 mTmpMatrix);
         bounds.transform(mTmpMatrix);
-        return DisplayCutout.fromBounds(bounds).computeSafeInsets(
+        return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds),
                 rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
                 rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
     }
@@ -1441,7 +1446,8 @@
 
     private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
             int uiMode, int dw, int dh) {
-        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
+        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(
+                rotation).getDisplayCutout();
         final int width = mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
                 displayId, displayCutout);
         if (width < displayInfo.smallestNominalAppWidth) {
@@ -2910,7 +2916,8 @@
             Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
         }
 
-        mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo);
+        mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
+                calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
         // TODO: Not sure if we really need to set the rotation here since we are updating from the
         // display info above...
         mDisplayFrames.mRotation = mRotation;
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 57ce15bc..57693ac 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -27,6 +27,8 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 
+import com.android.server.wm.utils.WmDisplayCutout;
+
 import java.io.PrintWriter;
 
 /**
@@ -97,10 +99,10 @@
     public final Rect mDock = new Rect();
 
     /** The display cutout used for layout (after rotation) */
-    @NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+    @NonNull public WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
 
     /** The cutout as supplied by display info */
-    @NonNull private DisplayCutout mDisplayInfoCutout = DisplayCutout.NO_CUTOUT;
+    @NonNull public WmDisplayCutout mDisplayInfoCutout = WmDisplayCutout.NO_CUTOUT;
 
     /**
      * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
@@ -114,19 +116,18 @@
 
     public int mRotation;
 
-    public DisplayFrames(int displayId, DisplayInfo info) {
+    public DisplayFrames(int displayId, DisplayInfo info, WmDisplayCutout displayCutout) {
         mDisplayId = displayId;
-        onDisplayInfoUpdated(info);
+        onDisplayInfoUpdated(info, displayCutout);
     }
 
-    public void onDisplayInfoUpdated(DisplayInfo info) {
+    public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout) {
         mDisplayWidth = info.logicalWidth;
         mDisplayHeight = info.logicalHeight;
         mRotation = info.rotation;
         mDisplayInfoOverscan.set(
                 info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
-        mDisplayInfoCutout = info.displayCutout != null
-                ? info.displayCutout : DisplayCutout.NO_CUTOUT;
+        mDisplayInfoCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
     }
 
     public void onBeginLayout() {
@@ -171,8 +172,8 @@
         mDisplayCutout = mDisplayInfoCutout;
         mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
                 Integer.MAX_VALUE, Integer.MAX_VALUE);
-        if (!mDisplayCutout.isEmpty()) {
-            final DisplayCutout c = mDisplayCutout;
+        if (!mDisplayCutout.getDisplayCutout().isEmpty()) {
+            final DisplayCutout c = mDisplayCutout.getDisplayCutout();
             if (c.getSafeInsetLeft() > 0) {
                 mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
             }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 1f1efc4..b99e85f 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -175,7 +175,7 @@
                     getContentWidth());
 
             final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(
-                    rotation);
+                    rotation).getDisplayCutout();
 
             // Since we only care about feasible states, snap to the closest snap target, like it
             // would happen when actually rotating the screen.
@@ -233,7 +233,7 @@
                     ? mDisplayContent.mBaseDisplayWidth
                     : mDisplayContent.mBaseDisplayHeight;
             final DisplayCutout displayCutout =
-                    mDisplayContent.calculateDisplayCutoutForRotation(rotation);
+                    mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
             mService.mPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
             config.unset();
             config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 1b41cb8..3f1fde9 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -16,12 +16,18 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.proto.AnimationAdapterProto.LOCAL;
+import static com.android.server.wm.proto.LocalAnimationAdapterProto.ANIMATION_SPEC;
+
 import android.os.SystemClock;
+import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
+import java.io.PrintWriter;
+
 /**
  * Animation that can be executed without holding the window manager lock. See
  * {@link SurfaceAnimationRunner}.
@@ -74,6 +80,18 @@
         return mSpec.calculateStatusBarTransitionStartTime();
     }
 
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        mSpec.dump(pw, prefix);
+    }
+
+    @Override
+    public void writeToProto(ProtoOutputStream proto) {
+        final long token = proto.start(LOCAL);
+        mSpec.writeToProto(proto, ANIMATION_SPEC);
+        proto.end(token);
+    }
+
     /**
      * Describes how to apply an animation.
      */
@@ -127,5 +145,15 @@
         default boolean canSkipFirstFrame() {
             return false;
         }
+
+        void dump(PrintWriter pw, String prefix);
+
+        default void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            writeToProtoInner(proto);
+            proto.end(token);
+        }
+
+        void writeToProtoInner(ProtoOutputStream proto);
     }
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 39b886d..59bec74 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -23,6 +23,8 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
 
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.WindowConfiguration;
@@ -33,18 +35,21 @@
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Slog;
+import android.util.Slog;import android.util.proto.ProtoOutputStream;
 import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationController;
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
 import com.google.android.collect.Sets;
+
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
-
 /**
  * Controls a single instance of the remote driven recents animation. In particular, this allows
  * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
@@ -348,6 +353,7 @@
         private SurfaceControl mCapturedLeash;
         private OnAnimationFinishedCallback mCapturedFinishCallback;
         private final boolean mIsRecentTaskInvisible;
+        private RemoteAnimationTarget mTarget;
 
         TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
             mTask = task;
@@ -361,10 +367,11 @@
             container.getRelativePosition(position);
             container.getBounds(bounds);
             final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
-            return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
+            mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
                     !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
                     mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
                     mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
+            return mTarget;
         }
 
         @Override
@@ -403,6 +410,26 @@
         public long getStatusBarTransitionsStartTime() {
             return SystemClock.uptimeMillis();
         }
+
+        @Override
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix); pw.println("task=" + mTask);
+            if (mTarget != null) {
+                pw.print(prefix); pw.println("Target:");
+                mTarget.dump(pw, prefix + "  ");
+            } else {
+                pw.print(prefix); pw.println("Target: null");
+            }
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream proto) {
+            final long token = proto.start(REMOTE);
+            if (mTarget != null) {
+                mTarget.writeToProto(proto, TARGET);
+            }
+            proto.end(token);
+        }
     }
 
     public void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 169d65e..d645110 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,8 +16,11 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -25,16 +28,18 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationFinishedCallback.Stub;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 
+import com.android.internal.util.FastPrintWriter;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
-import java.lang.ref.WeakReference;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 
 /**
@@ -104,6 +109,20 @@
             }
         });
         sendRunningRemoteAnimation(true);
+        if (DEBUG_APP_TRANSITIONS) {
+            writeStartDebugStatement();
+        }
+    }
+
+    private void writeStartDebugStatement() {
+        Slog.i(TAG, "Starting remote animation");
+        final StringWriter sw = new StringWriter();
+        final FastPrintWriter pw = new FastPrintWriter(sw);
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            mPendingAnimations.get(i).dump(pw, "");
+        }
+        pw.close();
+        Slog.i(TAG, sw.toString());
     }
 
     private RemoteAnimationTarget[] createAnimations() {
@@ -133,6 +152,7 @@
             }
         }
         sendRunningRemoteAnimation(false);
+        if (DEBUG_APP_TRANSITIONS) Slog.i(TAG, "Finishing remote animation");
     }
 
     private void invokeAnimationCancelled() {
@@ -193,6 +213,7 @@
         private OnAnimationFinishedCallback mCapturedFinishCallback;
         private final Point mPosition = new Point();
         private final Rect mStackBounds = new Rect();
+        private RemoteAnimationTarget mTarget;
 
         RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position,
                 Rect stackBounds) {
@@ -210,11 +231,12 @@
             if (mainWindow == null) {
                 return null;
             }
-            return new RemoteAnimationTarget(task.mTaskId, getMode(),
+            mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
                     mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
                     task.getWindowConfiguration(), false /*isNotInRecents*/);
+            return mTarget;
         }
 
         private int getMode() {
@@ -275,5 +297,25 @@
             return SystemClock.uptimeMillis()
                     + mRemoteAnimationAdapter.getStatusBarTransitionDelay();
         }
+
+        @Override
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix); pw.print("token="); pw.println(mAppWindowToken);
+            if (mTarget != null) {
+                pw.print(prefix); pw.println("Target:");
+                mTarget.dump(pw, prefix + "  ");
+            } else {
+                pw.print(prefix); pw.println("Target: null");
+            }
+        }
+
+        @Override
+        public void writeToProto(ProtoOutputStream proto) {
+            final long token = proto.start(REMOTE);
+            if (mTarget != null) {
+                mTarget.writeToProto(proto, TARGET);
+            }
+            proto.end(token);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 76f5396..c06caaf 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -313,7 +313,9 @@
      */
     void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        proto.write(ANIMATION_ADAPTER, mAnimation != null ? mAnimation.toString() : "null");
+        if (mAnimation != null) {
+            mAnimation.writeToProto(proto, ANIMATION_ADAPTER);
+        }
         if (mLeash != null){
             mLeash.writeToProto(proto, LEASH);
         }
@@ -322,8 +324,18 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("mAnimation="); pw.print(mAnimation);
-        pw.print(" mLeash="); pw.println(mLeash);
+        pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
+        if (mAnimationStartDelayed) {
+            pw.print(" mAnimationStartDelayed="); pw.println(mAnimationStartDelayed);
+        } else {
+            pw.println();
+        }
+        pw.print(prefix); pw.println("Animation:");
+        if (mAnimation != null) {
+            mAnimation.dump(pw, prefix + "  ");
+        } else {
+            pw.print(prefix); pw.println("null");
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index a5a1ca5..9310dc4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -273,7 +273,8 @@
         }
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
                 getInsetsFromTaskBounds(mainWindow, task),
-                isLowRamDevice /* reduced */, scaleFraction /* scale */);
+                isLowRamDevice /* reduced */, scaleFraction /* scale */,
+                true /* isRealSnapshot */);
     }
 
     private boolean shouldDisableSnapshots() {
@@ -369,7 +370,8 @@
         }
         return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
                 topChild.getConfiguration().orientation, mainWindow.mStableInsets,
-                ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */);
+                ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */,
+                false /* isRealSnapshot */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 537f317..31da5f3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -89,7 +89,8 @@
             }
             return new TaskSnapshot(buffer, proto.orientation,
                     new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
-                    reducedResolution, reducedResolution ? REDUCED_SCALE : 1f);
+                    reducedResolution, reducedResolution ? REDUCED_SCALE : 1f,
+                    proto.isRealSnapshot);
         } catch (IOException e) {
             Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
             return null;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 621bee7..086fffa 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -318,6 +318,7 @@
             proto.insetTop = mSnapshot.getContentInsets().top;
             proto.insetRight = mSnapshot.getContentInsets().right;
             proto.insetBottom = mSnapshot.getContentInsets().bottom;
+            proto.isRealSnapshot = mSnapshot.isRealSnapshot();
             final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
             final File file = getProtoFile(mTaskId, mUserId);
             final AtomicFile atomicFile = new AtomicFile(file);
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 43fa3d5..a41eba8 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -19,10 +19,13 @@
 import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
+import static com.android.server.wm.proto.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.proto.WindowAnimationSpecProto.ANIMATION;
 
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.animation.Animation;
@@ -33,6 +36,8 @@
 
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 
+import java.io.PrintWriter;
+
 /**
  * Animation spec for regular window animations.
  */
@@ -129,6 +134,18 @@
         return mCanSkipFirstFrame;
     }
 
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.println(mAnimation);
+    }
+
+    @Override
+    public void writeToProtoInner(ProtoOutputStream proto) {
+        final long token = proto.start(WINDOW);
+        proto.write(ANIMATION, mAnimation.toString());
+        proto.end(token);
+    }
+
     /**
      * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ded81d..563d792 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1438,7 +1438,9 @@
 
             final DisplayFrames displayFrames = displayContent.mDisplayFrames;
             // TODO: Not sure if onDisplayInfoUpdated() call is needed.
-            displayFrames.onDisplayInfoUpdated(displayContent.getDisplayInfo());
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            displayFrames.onDisplayInfoUpdated(displayInfo,
+                    displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation));
             final Rect taskBounds;
             if (atoken != null && atoken.getTask() != null) {
                 taskBounds = mTmpRect;
@@ -2097,7 +2099,7 @@
             win.mLastRelayoutContentInsets.set(win.mContentInsets);
             outVisibleInsets.set(win.mVisibleInsets);
             outStableInsets.set(win.mStableInsets);
-            outCutout.set(win.mDisplayCutout);
+            outCutout.set(win.mDisplayCutout.getDisplayCutout());
             outOutsets.set(win.mOutsets);
             outBackdropFrame.set(win.getBackdropFrame(win.mFrame));
             if (localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c4185fa..297e067 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -113,6 +113,10 @@
 import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.proto.IdentifierProto.TITLE;
 import static com.android.server.wm.proto.IdentifierProto.USER_ID;
+import static com.android.server.wm.proto.AnimationSpecProto.MOVE;
+import static com.android.server.wm.proto.MoveAnimationSpecProto.DURATION;
+import static com.android.server.wm.proto.MoveAnimationSpecProto.FROM;
+import static com.android.server.wm.proto.MoveAnimationSpecProto.TO;
 import static com.android.server.wm.proto.WindowStateProto.ANIMATING_EXIT;
 import static com.android.server.wm.proto.WindowStateProto.ANIMATOR;
 import static com.android.server.wm.proto.WindowStateProto.ATTRIBUTES;
@@ -202,6 +206,7 @@
 import com.android.server.input.InputWindowHandle;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -351,8 +356,8 @@
     private boolean mOutsetsChanged = false;
 
     /** Part of the display that has been cut away. See {@link DisplayCutout}. */
-    DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
-    private DisplayCutout mLastDisplayCutout = DisplayCutout.NO_CUTOUT;
+    WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
+    private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT;
     private boolean mDisplayCutoutChanged;
 
     /**
@@ -693,6 +698,7 @@
         mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
         mWindowId = new WindowId(this);
         mAttrs.copyFrom(a);
+        mLastSurfaceInsets.set(mAttrs.surfaceInsets);
         mViewVisibility = viewVisibility;
         mPolicy = mService.mPolicy;
         mContext = mService.mContext;
@@ -833,7 +839,7 @@
     @Override
     public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
             Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
-            Rect outsetFrame, DisplayCutout displayCutout) {
+            Rect outsetFrame, WmDisplayCutout displayCutout) {
         if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
@@ -2914,7 +2920,7 @@
             final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
             final boolean reportOrientation = mReportOrientationChanged;
             final int displayId = getDisplayId();
-            final DisplayCutout displayCutout = mDisplayCutout;
+            final DisplayCutout displayCutout = mDisplayCutout.getDisplayCutout();
             if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                     && mClient instanceof IWindow.Stub) {
                 // To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -3186,7 +3192,7 @@
         mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
         mStableInsets.writeToProto(proto, STABLE_INSETS);
         mOutsets.writeToProto(proto, OUTSETS);
-        mDisplayCutout.writeToProto(proto, CUTOUT);
+        mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
         proto.write(REMOVE_ON_EXIT, mRemoveOnExit);
         proto.write(DESTROYING, mDestroying);
         proto.write(REMOVED, mRemoved);
@@ -3332,7 +3338,7 @@
                     pw.print(" stable="); mStableInsets.printShortString(pw);
                     pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
                     pw.print(" outsets="); mOutsets.printShortString(pw);
-                    pw.print(" cutout=" + mDisplayCutout);
+            pw.print(" cutout=" + mDisplayCutout.getDisplayCutout());
                     pw.println();
             pw.print(prefix); pw.print("Lst insets: overscan=");
                     mLastOverscanInsets.printShortString(pw);
@@ -4722,5 +4728,21 @@
             t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
                     mFrom.y + (mTo.y - mFrom.y) * v);
         }
+
+        @Override
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix); pw.print("from="); pw.print(mFrom);
+            pw.print(" to="); pw.print(mTo);
+            pw.print(" duration="); pw.println(mDuration);
+        }
+
+        @Override
+        public void writeToProtoInner(ProtoOutputStream proto) {
+            final long token = proto.start(MOVE);
+            mFrom.writeToProto(proto, FROM);
+            mTo.writeToProto(proto, TO);
+            proto.write(DURATION, mDuration);
+            proto.end(token);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
new file mode 100644
index 0000000..ea3f758
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm.utils;
+
+import android.graphics.Rect;
+import android.util.Size;
+import android.view.DisplayCutout;
+import android.view.Gravity;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Wrapper for DisplayCutout that also tracks the display size and using this allows (re)calculating
+ * safe insets.
+ */
+public class WmDisplayCutout {
+
+    public static final WmDisplayCutout NO_CUTOUT = new WmDisplayCutout(DisplayCutout.NO_CUTOUT,
+            null);
+
+    private final DisplayCutout mInner;
+    private final Size mFrameSize;
+
+    public WmDisplayCutout(DisplayCutout inner, Size frameSize) {
+        mInner = inner;
+        mFrameSize = frameSize;
+    }
+
+    public static WmDisplayCutout computeSafeInsets(DisplayCutout inner,
+            int displayWidth, int displayHeight) {
+        if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) {
+            return NO_CUTOUT;
+        }
+
+        final Size displaySize = new Size(displayWidth, displayHeight);
+        final Rect safeInsets = computeSafeInsets(displaySize, inner);
+        return new WmDisplayCutout(inner.replaceSafeInsets(safeInsets), displaySize);
+    }
+
+    /**
+     * Insets the reference frame of the cutout in the given directions.
+     *
+     * @return a copy of this instance which has been inset
+     * @hide
+     */
+    public WmDisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
+        DisplayCutout newInner = mInner.inset(insetLeft, insetTop, insetRight, insetBottom);
+
+        if (mInner == newInner) {
+            return this;
+        }
+
+        Size frame = mFrameSize == null ? null : new Size(
+                mFrameSize.getWidth() - insetLeft - insetRight,
+                mFrameSize.getHeight() - insetTop - insetBottom);
+
+        return new WmDisplayCutout(newInner, frame);
+    }
+
+    /**
+     * Recalculates the cutout relative to the given reference frame.
+     *
+     * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}.
+     *
+     * @return a copy of this instance with the safe insets recalculated
+     * @hide
+     */
+    public WmDisplayCutout calculateRelativeTo(Rect frame) {
+        if (mInner.isEmpty()) {
+            return this;
+        }
+        return inset(frame.left, frame.top,
+                mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom);
+    }
+
+    /**
+     * Calculates the safe insets relative to the given display size.
+     *
+     * @return a copy of this instance with the safe insets calculated
+     * @hide
+     */
+    public WmDisplayCutout computeSafeInsets(int width, int height) {
+        return computeSafeInsets(mInner, width, height);
+    }
+
+    private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) {
+        if (displaySize.getWidth() < displaySize.getHeight()) {
+            final List<Rect> boundingRects = cutout.replaceSafeInsets(
+                    new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2))
+                    .getBoundingRects();
+            int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP);
+            int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM);
+            return new Rect(0, topInset, 0, bottomInset);
+        } else if (displaySize.getWidth() > displaySize.getHeight()) {
+            final List<Rect> boundingRects = cutout.replaceSafeInsets(
+                    new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0))
+                    .getBoundingRects();
+            int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT);
+            int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT);
+            return new Rect(leftInset, 0, right, 0);
+        } else {
+            throw new UnsupportedOperationException("not implemented: display=" + displaySize +
+                    " cutout=" + cutout);
+        }
+    }
+
+    private static int findInsetForSide(Size display, List<Rect> boundingRects, int gravity) {
+        int inset = 0;
+        final int size = boundingRects.size();
+        for (int i = 0; i < size; i++) {
+            Rect boundingRect = boundingRects.get(i);
+            switch (gravity) {
+                case Gravity.TOP:
+                    if (boundingRect.top == 0) {
+                        inset = Math.max(inset, boundingRect.bottom);
+                    }
+                    break;
+                case Gravity.BOTTOM:
+                    if (boundingRect.bottom == display.getHeight()) {
+                        inset = Math.max(inset, display.getHeight() - boundingRect.top);
+                    }
+                    break;
+                case Gravity.LEFT:
+                    if (boundingRect.left == 0) {
+                        inset = Math.max(inset, boundingRect.right);
+                    }
+                    break;
+                case Gravity.RIGHT:
+                    if (boundingRect.right == display.getWidth()) {
+                        inset = Math.max(inset, display.getWidth() - boundingRect.left);
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown gravity: " + gravity);
+            }
+        }
+        return inset;
+    }
+
+    public DisplayCutout getDisplayCutout() {
+        return mInner;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof WmDisplayCutout)) {
+            return false;
+        }
+        WmDisplayCutout that = (WmDisplayCutout) o;
+        return Objects.equals(mInner, that.mInner) &&
+                Objects.equals(mFrameSize, that.mFrameSize);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mInner, mFrameSize);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java
new file mode 100644
index 0000000..322db85
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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
+ */
+
+package com.android.server.backup.transport;
+
+import static com.android.server.backup.testing.TransportData.backupTransport;
+import static com.android.server.backup.testing.TransportData.d2dTransport;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.transport.TransportStats.Stats;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TransportStatsTest {
+    private static final double TOLERANCE = 0.0001;
+
+    private TransportStats mTransportStats;
+    private ComponentName mTransportComponent1;
+    private ComponentName mTransportComponent2;
+
+    @Before
+    public void setUp() throws Exception {
+        mTransportStats = new TransportStats();
+        mTransportComponent1 = backupTransport().getTransportComponent();
+        mTransportComponent2 = d2dTransport().getTransportComponent();
+    }
+
+    @Test
+    public void testRegisterConnectionTime() {
+        mTransportStats.registerConnectionTime(mTransportComponent1, 50L);
+
+        Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+        assertThat(stats.average).isWithin(TOLERANCE).of(50);
+        assertThat(stats.max).isEqualTo(50L);
+        assertThat(stats.min).isEqualTo(50L);
+        assertThat(stats.n).isEqualTo(1);
+    }
+
+    @Test
+    public void testRegisterConnectionTime_whenHasAlreadyOneSample() {
+        mTransportStats.registerConnectionTime(mTransportComponent1, 50L);
+
+        mTransportStats.registerConnectionTime(mTransportComponent1, 100L);
+
+        Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+        assertThat(stats.average).isWithin(TOLERANCE).of(75);
+        assertThat(stats.max).isEqualTo(100L);
+        assertThat(stats.min).isEqualTo(50L);
+        assertThat(stats.n).isEqualTo(2);
+    }
+
+    @Test
+    public void testGetStatsForTransport() {
+        mTransportStats.registerConnectionTime(mTransportComponent1, 10L);
+        mTransportStats.registerConnectionTime(mTransportComponent2, 20L);
+
+        Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+
+        assertThat(stats.average).isWithin(TOLERANCE).of(10);
+        assertThat(stats.max).isEqualTo(10L);
+        assertThat(stats.min).isEqualTo(10L);
+        assertThat(stats.n).isEqualTo(1);
+    }
+
+    @Test
+    public void testMerge() {
+        mTransportStats.registerConnectionTime(mTransportComponent1, 10L);
+        mTransportStats.registerConnectionTime(mTransportComponent2, 20L);
+        Stats stats1 = mTransportStats.getStatsForTransport(mTransportComponent1);
+        Stats stats2 = mTransportStats.getStatsForTransport(mTransportComponent2);
+
+        Stats stats = Stats.merge(stats1, stats2);
+
+        assertThat(stats.average).isWithin(TOLERANCE).of(15);
+        assertThat(stats.max).isEqualTo(20L);
+        assertThat(stats.min).isEqualTo(10L);
+        assertThat(stats.n).isEqualTo(2);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 5b1f5c1..ac212dd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -123,12 +123,20 @@
             }
             return null;
         }).when(mActivity.app.thread).scheduleTransaction(any());
+
         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
 
+        // The activity is in the focused stack so it should not move to paused.
         mActivity.makeVisibleIfNeeded(null /* starting */);
+        assertTrue(mActivity.isState(STOPPED));
+        assertFalse(pauseFound.value);
 
+        // Clear focused stack
+        mActivity.mStackSupervisor.mFocusedStack = null;
+
+        // In the unfocused stack, the activity should move to paused.
+        mActivity.makeVisibleIfNeeded(null /* starting */);
         assertTrue(mActivity.isState(PAUSING));
-
         assertTrue(pauseFound.value);
 
         // Make sure that the state does not change for current non-stopping states.
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
index d5a28f6..c348e70 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -27,6 +27,8 @@
 
 @RunWith(JUnit4.class)
 public class AutofillManagerServiceTest {
+    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
+    private static final boolean ADDS_DEFAULT_BUTTON = true;
 
     @Test
     public void testGetWhitelistedCompatModePackages_null() {
@@ -40,8 +42,16 @@
 
     @Test
     public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
-        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
-                .containsExactly("one_is_the_loniest_package", null);
+        if (ADDS_DEFAULT_BUTTON) {
+            final Map<String, String[]> result =
+                    getWhitelistedCompatModePackages("one_is_the_loniest_package");
+            assertThat(result).hasSize(1);
+            assertThat(result.get("one_is_the_loniest_package")).asList()
+                    .containsExactly("url_bar", "location_bar_edit_text");
+        } else {
+            assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+                    .containsExactly("one_is_the_loniest_package", null);
+        }
     }
 
     @Test
@@ -70,7 +80,12 @@
     public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
         final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
         assertThat(result).hasSize(1);
-        assertThat(result.get("one")).isNull();
+        if (ADDS_DEFAULT_BUTTON) {
+            assertThat(result.get("one")).asList()
+                    .containsExactly("url_bar", "location_bar_edit_text");
+        } else {
+            assertThat(result.get("one")).isNull();
+        }
     }
 
     @Test
@@ -79,7 +94,12 @@
                 getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
         assertThat(result).hasSize(3);
         assertThat(result.get("p1")).asList().containsExactly("p1u1");
-        assertThat(result.get("p2")).isNull();
+        if (ADDS_DEFAULT_BUTTON) {
+            assertThat(result.get("p2")).asList()
+                    .containsExactly("url_bar", "location_bar_edit_text");
+        } else {
+            assertThat(result.get("p2")).isNull();
+        }
         assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index 5de393c..f3539fe 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -25,6 +25,8 @@
 import android.view.IApplicationToken;
 import android.view.WindowManager;
 
+import com.android.server.wm.utils.WmDisplayCutout;
+
 public class FakeWindowState implements WindowManagerPolicy.WindowState {
 
     public final Rect parentFrame = new Rect();
@@ -36,7 +38,7 @@
     public final Rect stableFrame = new Rect();
     public Rect outsetFrame = new Rect();
 
-    public DisplayCutout displayCutout;
+    public WmDisplayCutout displayCutout;
 
     public WindowManager.LayoutParams attrs;
     public int displayId;
@@ -61,7 +63,7 @@
     @Override
     public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame,
             Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
-            @Nullable Rect outsetFrame, DisplayCutout displayCutout) {
+            @Nullable Rect outsetFrame, WmDisplayCutout displayCutout) {
         this.parentFrame.set(parentFrame);
         this.displayFrame.set(displayFrame);
         this.overscanFrame.set(overlayFrame);
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 1d4348c..195dd39 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -41,6 +41,7 @@
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
 import android.testing.TestableResources;
+import android.util.Pair;
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
@@ -53,6 +54,7 @@
 
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.wm.DisplayFrames;
+import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
 
@@ -98,8 +100,9 @@
     }
 
     private void updateDisplayFrames() {
-        DisplayInfo info = displayInfoForRotation(mRotation, mHasDisplayCutout);
-        mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info);
+        Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
+                mHasDisplayCutout);
+        mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info.first, info.second);
     }
 
     public void addStatusBar() {
@@ -146,19 +149,26 @@
     }
 
     public static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
+        return displayInfoAndCutoutForRotation(rotation, withDisplayCutout).first;
+    }
+    public static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
+            boolean withDisplayCutout) {
         DisplayInfo info = new DisplayInfo();
+        WmDisplayCutout cutout = null;
 
         final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
         info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
         info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
         info.rotation = rotation;
         if (withDisplayCutout) {
-            info.displayCutout = displayCutoutForRotation(rotation)
-                    .computeSafeInsets(info.logicalWidth, info.logicalHeight);
+            cutout = WmDisplayCutout.computeSafeInsets(
+                    displayCutoutForRotation(rotation), info.logicalWidth,
+                    info.logicalHeight);
+            info.displayCutout = cutout.getDisplayCutout();
         } else {
             info.displayCutout = null;
         }
-        return info;
+        return Pair.create(info, cutout);
     }
 
     private static DisplayCutout displayCutoutForRotation(int rotation) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 064e077..ccde049 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -50,6 +50,8 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 
+import com.android.server.wm.utils.WmDisplayCutout;
+
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -398,8 +400,9 @@
             dc.mInitialDisplayWidth = 200;
             dc.mInitialDisplayHeight = 400;
             Rect r = new Rect(80, 0, 120, 10);
-            final DisplayCutout cutout = fromBoundingRect(r.left, r.top, r.right, r.bottom)
-                    .computeSafeInsets(200, 400);
+            final DisplayCutout cutout = new WmDisplayCutout(
+                    fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
+                    .computeSafeInsets(200, 400).getDisplayCutout();
 
             dc.mInitialDisplayCutout = cutout;
             dc.setRotation(Surface.ROTATION_0);
@@ -416,16 +419,18 @@
             dc.mInitialDisplayWidth = 200;
             dc.mInitialDisplayHeight = 400;
             Rect r1 = new Rect(80, 0, 120, 10);
-            final DisplayCutout cutout = fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom)
-                    .computeSafeInsets(200, 400);
+            final DisplayCutout cutout = new WmDisplayCutout(
+                    fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null)
+                    .computeSafeInsets(200, 400).getDisplayCutout();
 
             dc.mInitialDisplayCutout = cutout;
             dc.setRotation(Surface.ROTATION_90);
             dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
 
             final Rect r = new Rect(0, 80, 10, 120);
-            assertEquals(fromBoundingRect(r.left, r.top, r.right, r.bottom)
-                    .computeSafeInsets(400, 200), dc.getDisplayInfo().displayCutout);
+            assertEquals(new WmDisplayCutout(
+                    fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
+                    .computeSafeInsets(400, 200).getDisplayCutout(), dc.getDisplayInfo().displayCutout);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 96fbc14..80cbf2a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -42,7 +42,7 @@
 /**
  * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
  *
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotPersisterLoaderTest
+ * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
  */
 @MediumTest
 @Presubmit
@@ -163,6 +163,23 @@
     }
 
     @Test
+    public void testIsRealSnapshotPersistAndLoadSnapshot() {
+        TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */);
+        TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */);
+        assertTrue(a.isRealSnapshot());
+        assertFalse(b.isRealSnapshot());
+        mPersister.persistSnapshot(1, mTestUserId, a);
+        mPersister.persistSnapshot(2, mTestUserId, b);
+        mPersister.waitForQueueEmpty();
+        final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
+        final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
+        assertNotNull(snapshotA);
+        assertNotNull(snapshotB);
+        assertTrue(snapshotA.isRealSnapshot());
+        assertFalse(snapshotB.isRealSnapshot());
+    }
+
+    @Test
     public void testRemoveObsoleteFiles() {
         mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
         mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index b49a0fd..2ad5bf4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -84,12 +84,16 @@
     }
 
     TaskSnapshot createSnapshot(float scale) {
+        return createSnapshot(scale, true /* isRealSnapshot */);
+    }
+
+    TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot) {
         final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
                 USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
         Canvas c = buffer.lockCanvas();
         c.drawColor(Color.RED);
         buffer.unlockCanvasAndPost(c);
         return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS,
-                scale < 1f /* reducedResolution */, scale);
+                scale < 1f /* reducedResolution */, scale, isRealSnapshot);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 4288eac..d5334ba 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -60,7 +60,7 @@
         final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
                 GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
         final TaskSnapshot snapshot = new TaskSnapshot(buffer,
-                ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
+                ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */);
         mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
                 Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
                 ORIENTATION_PORTRAIT);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index b5d5fc6..bd212a9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -26,7 +26,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IWindow;
@@ -38,6 +37,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import com.android.server.wm.utils.WmDisplayCutout;
+
 /**
  * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
  *
@@ -159,7 +160,7 @@
         // When mFrame extends past cf, the content insets are
         // the difference between mFrame and ContentFrame. Visible
         // and stable frames work the same way.
-        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame,0, 0, 1000, 1000);
         assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset);
         assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset);
@@ -174,7 +175,7 @@
         w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
         w.mRequestedWidth = 100;
         w.mRequestedHeight = 100;
-        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 100, 100, 200, 200);
         assertRect(w.mContentInsets, 0, 0, 0, 0);
         // In this case the frames are shrunk to the window frame.
@@ -195,7 +196,7 @@
 
         // Here the window has FILL_PARENT, FILL_PARENT
         // so we expect it to fill the entire available frame.
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 0, 0, 1000, 1000);
 
         // It can select various widths and heights within the bounds.
@@ -203,14 +204,14 @@
         // and we use mRequestedWidth/mRequestedHeight
         w.mAttrs.width = 300;
         w.mAttrs.height = 300;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         // Explicit width and height without requested width/height
         // gets us nothing.
         assertRect(w.mFrame, 0, 0, 0, 0);
 
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         // With requestedWidth/Height we can freely choose our size within the
         // parent bounds.
         assertRect(w.mFrame, 0, 0, 300, 300);
@@ -223,14 +224,14 @@
         w.mRequestedWidth = -1;
         w.mAttrs.width = 100;
         w.mAttrs.height = 100;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 0, 0, 100, 100);
         w.mAttrs.flags = 0;
 
         // But sizes too large will be clipped to the containing frame
         w.mRequestedWidth = 1200;
         w.mRequestedHeight = 1200;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 0, 0, 1000, 1000);
 
         // Before they are clipped though windows will be shifted
@@ -238,7 +239,7 @@
         w.mAttrs.y = 300;
         w.mRequestedWidth = 1000;
         w.mRequestedHeight = 1000;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 0, 0, 1000, 1000);
 
         // If there is room to move around in the parent frame the window will be shifted according
@@ -248,16 +249,16 @@
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 700, 0, 1000, 300);
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 700, 700, 1000, 1000);
         // Window specified  x and y are interpreted as offsets in the opposite
         // direction of gravity
         w.mAttrs.x = 100;
         w.mAttrs.y = 100;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, 600, 600, 900, 900);
     }
 
@@ -278,7 +279,7 @@
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT);
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -290,7 +291,7 @@
         final int cfRight = logicalWidth / 2;
         final int cfBottom = logicalHeight / 2;
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
-        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
         int contentInsetRight = taskRight - cfRight;
         int contentInsetBottom = taskBottom - cfBottom;
@@ -307,7 +308,7 @@
         final int insetRight = insetLeft + (taskRight - taskLeft);
         final int insetBottom = insetTop + (taskBottom - taskTop);
         task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
-        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT);
         assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
         contentInsetRight = insetRight - cfRight;
         contentInsetBottom = insetBottom - cfBottom;
@@ -339,13 +340,13 @@
 
         final Rect policyCrop = new Rect();
 
-        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT);
         w.calculatePolicyCrop(policyCrop);
         assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom);
 
         dcf.setEmpty();
         // Likewise with no decor frame we would get no crop
-        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT);
         w.calculatePolicyCrop(policyCrop);
         assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
 
@@ -358,7 +359,7 @@
         w.mAttrs.height = logicalHeight / 2;
         w.mRequestedWidth = logicalWidth / 2;
         w.mRequestedHeight = logicalHeight / 2;
-        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT);
 
         w.calculatePolicyCrop(policyCrop);
         // Normally the crop is shrunk from the decor frame
@@ -395,7 +396,7 @@
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
                 pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */,
-                pf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
+                pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT);
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -414,7 +415,7 @@
 
         w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
                 cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */,
-                cf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
+                cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT);
         assertEquals(cf, w.mFrame);
         assertEquals(cf, w.getContentFrameLw());
         assertRect(w.mContentInsets, 0, 0, 0, 0);
@@ -427,17 +428,17 @@
         WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
-        final Rect pf = new Rect(0, 0, 1000, 1000);
+        final Rect pf = new Rect(0, 0, 1000, 2000);
         // Create a display cutout of size 50x50, aligned top-center
-        final DisplayCutout cutout = fromBoundingRect(500, 0, 550, 50)
-                .computeSafeInsets(pf.width(), pf.height());
+        final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height());
 
         w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout);
 
-        assertEquals(w.mDisplayCutout.getSafeInsetTop(), 50);
-        assertEquals(w.mDisplayCutout.getSafeInsetBottom(), 0);
-        assertEquals(w.mDisplayCutout.getSafeInsetLeft(), 0);
-        assertEquals(w.mDisplayCutout.getSafeInsetRight(), 0);
+        assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetTop(), 50);
+        assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetBottom(), 0);
+        assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetLeft(), 0);
+        assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetRight(), 0);
     }
 
     private WindowStateWithTask createWindow(Task task, int width, int height) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
new file mode 100644
index 0000000..f7addf6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm.utils;
+
+
+import static android.view.DisplayCutout.NO_CUTOUT;
+import static android.view.DisplayCutout.fromBoundingRect;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Size;
+import android.view.DisplayCutout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link WmDisplayCutout}
+ *
+ * Run with: atest WmDisplayCutoutTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class WmDisplayCutoutTest {
+
+    private final DisplayCutout mCutoutTop = new DisplayCutout(
+            new Rect(0, 100, 0, 0),
+            Arrays.asList(new Rect(50, 0, 75, 100)));
+
+    @Test
+    public void calculateRelativeTo_top() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 0, 100, 20), 200, 400)
+                .calculateRelativeTo(new Rect(5, 5, 95, 195));
+
+        assertEquals(new Rect(0, 15, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void calculateRelativeTo_left() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 0, 20, 100), 400, 200)
+                .calculateRelativeTo(new Rect(5, 5, 195, 95));
+
+        assertEquals(new Rect(15, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void calculateRelativeTo_bottom() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 180, 100, 200), 100, 200)
+                .calculateRelativeTo(new Rect(5, 5, 95, 195));
+
+        assertEquals(new Rect(0, 0, 0, 15), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void calculateRelativeTo_right() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(180, 0, 200, 100), 200, 100)
+                .calculateRelativeTo(new Rect(5, 5, 195, 95));
+
+        assertEquals(new Rect(0, 0, 15, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void calculateRelativeTo_bounds() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 0, 100, 20), 200, 400)
+                .calculateRelativeTo(new Rect(5, 10, 95, 180));
+
+        assertEquals(new Rect(-5, -10, 95, 10), cutout.getDisplayCutout().getBounds().getBounds());
+    }
+
+    @Test
+    public void computeSafeInsets_top() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 0, 100, 20), 200, 400);
+
+        assertEquals(new Rect(0, 20, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void computeSafeInsets_left() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 0, 20, 100), 400, 200);
+
+        assertEquals(new Rect(20, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void computeSafeInsets_bottom() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(0, 180, 100, 200), 100, 200);
+
+        assertEquals(new Rect(0, 0, 0, 20), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void computeSafeInsets_right() {
+        WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+                fromBoundingRect(180, 0, 200, 100), 200, 100);
+
+        assertEquals(new Rect(0, 0, 20, 0), cutout.getDisplayCutout().getSafeInsets());
+    }
+
+    @Test
+    public void computeSafeInsets_bounds() {
+        DisplayCutout cutout = WmDisplayCutout.computeSafeInsets(mCutoutTop, 1000,
+                2000).getDisplayCutout();
+
+        assertEquals(mCutoutTop.getBounds().getBounds(),
+                cutout.getBounds().getBounds());
+    }
+
+    @Test
+    public void test_equals() {
+        assertEquals(new WmDisplayCutout(NO_CUTOUT, null), new WmDisplayCutout(NO_CUTOUT, null));
+        assertEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)),
+                new WmDisplayCutout(mCutoutTop, new Size(1, 2)));
+
+        assertNotEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)),
+                new WmDisplayCutout(mCutoutTop, new Size(5, 6)));
+        assertNotEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)),
+                new WmDisplayCutout(NO_CUTOUT, new Size(1, 2)));
+    }
+
+    @Test
+    public void test_hashCode() {
+        assertEquals(new WmDisplayCutout(NO_CUTOUT, null).hashCode(),
+                new WmDisplayCutout(NO_CUTOUT, null).hashCode());
+        assertEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode(),
+                new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode());
+    }
+}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index a92f7e7..cb64c9c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -21,6 +21,7 @@
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
@@ -389,6 +390,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyLights();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -400,6 +402,7 @@
         verifyBeepLooped();
         verifyNeverVibrate();
         verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -409,6 +412,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyBeep();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -418,6 +422,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyNeverBeep();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
@@ -429,6 +434,7 @@
 
         verifyNeverBeep();
         verifyNeverVibrate();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
@@ -440,6 +446,7 @@
 
         verifyNeverBeep();
         verifyNeverVibrate();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
@@ -455,6 +462,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyBeepLooped();
         verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -482,6 +490,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyNeverStopAudio();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -494,6 +503,8 @@
         mService.buzzBeepBlinkLocked(s);
 
         verifyNeverStopAudio();
+        assertTrue(r.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -511,6 +522,7 @@
         // should not stop noise, since we no longer own it
         mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
         verifyNeverStopAudio();
+        assertTrue(other.isInterruptive());
     }
 
     @Test
@@ -535,11 +547,13 @@
 
         // set up internal state
         mService.buzzBeepBlinkLocked(r);
+        assertTrue(r.isInterruptive());
         Mockito.reset(mRingtonePlayer);
 
         // quiet update should stop making noise
         mService.buzzBeepBlinkLocked(s);
         verifyStopAudio();
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -550,11 +564,13 @@
 
         // set up internal state
         mService.buzzBeepBlinkLocked(r);
+        assertTrue(r.isInterruptive());
         Mockito.reset(mRingtonePlayer);
 
         // stop making noise - this is a weird corner case, but quiet should override once
         mService.buzzBeepBlinkLocked(s);
         verifyStopAudio();
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -570,6 +586,7 @@
 
         verify(mService, times(1)).playInCallNotification();
         verifyNeverBeep(); // doesn't play normal beep
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -587,6 +604,7 @@
 
         verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
                 eq(effect), (AudioAttributes) anyObject());
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -603,6 +621,7 @@
 
         verifyNeverVibrate();
         verifyBeepLooped();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -621,6 +640,7 @@
                 eq(FALLBACK_VIBRATION), (AudioAttributes) anyObject());
         verify(mRingtonePlayer, never()).playAsync
                 (anyObject(), anyObject(), anyBoolean(), anyObject());
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -636,6 +656,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyDelayedVibrateLooped();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -646,18 +667,20 @@
 
         verifyNeverBeep();
         verifyVibrate();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
-    public void testInsistentVibrate() throws Exception {
+    public void testInsistentVibrate() {
         NotificationRecord r = getInsistentBuzzyNotification();
 
         mService.buzzBeepBlinkLocked(r);
         verifyVibrateLooped();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
-    public void testVibrateTwice() throws Exception {
+    public void testVibrateTwice() {
         NotificationRecord r = getBuzzyNotification();
 
         // set up internal state
@@ -668,6 +691,7 @@
         r.isUpdate = true;
         mService.buzzBeepBlinkLocked(r);
         verifyVibrate();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -677,6 +701,7 @@
         mService.buzzBeepBlinkLocked(child);
 
         verifyNeverBeep();
+        assertFalse(child.isInterruptive());
     }
 
     @Test
@@ -687,6 +712,7 @@
         mService.buzzBeepBlinkLocked(summary);
 
         verifyBeepLooped();
+        assertTrue(summary.isInterruptive());
     }
 
     @Test
@@ -696,6 +722,7 @@
         mService.buzzBeepBlinkLocked(nonGroup);
 
         verifyBeepLooped();
+        assertTrue(nonGroup.isInterruptive());
     }
 
     @Test
@@ -706,6 +733,7 @@
         mService.buzzBeepBlinkLocked(summary);
 
         verifyNeverBeep();
+        assertFalse(summary.isInterruptive());
     }
 
     @Test
@@ -715,6 +743,7 @@
         mService.buzzBeepBlinkLocked(child);
 
         verifyBeepLooped();
+        assertTrue(child.isInterruptive());
     }
 
     @Test
@@ -724,6 +753,7 @@
         mService.buzzBeepBlinkLocked(nonGroup);
 
         verifyBeepLooped();
+        assertTrue(nonGroup.isInterruptive());
     }
 
     @Test
@@ -733,6 +763,7 @@
         mService.buzzBeepBlinkLocked(group);
 
         verifyBeepLooped();
+        assertTrue(group.isInterruptive());
     }
 
     @Test
@@ -744,10 +775,12 @@
         // set up internal state
         mService.buzzBeepBlinkLocked(r);
         Mockito.reset(mVibrator);
+        assertTrue(r.isInterruptive());
 
         // update should not beep
         mService.buzzBeepBlinkLocked(s);
         verifyNeverVibrate();
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -759,6 +792,7 @@
         mService.buzzBeepBlinkLocked(r);
 
         verifyNeverStopVibrate();
+        assertTrue(r.isInterruptive());
     }
 
     @Test
@@ -771,6 +805,8 @@
         mService.buzzBeepBlinkLocked(s);
 
         verifyNeverStopVibrate();
+        assertTrue(r.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -788,6 +824,9 @@
         // should not stop vibrate, since we no longer own it
         mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
         verifyNeverStopVibrate();
+        assertTrue(r.isInterruptive());
+        assertTrue(other.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -802,10 +841,11 @@
         // should not stop noise, since it does not own it
         mService.buzzBeepBlinkLocked(other);
         verifyNeverStopVibrate();
+        assertFalse(other.isInterruptive());
     }
 
     @Test
-    public void testQuietUpdateCancelsVibrate() throws Exception {
+    public void testQuietUpdateCancelsVibrate() {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getQuietNotification();
         s.isUpdate = true;
@@ -817,6 +857,8 @@
         // quiet update should stop making noise
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
+        assertTrue(r.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -832,6 +874,8 @@
         // stop making noise - this is a weird corner case, but quiet should override once
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
+        assertTrue(r.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -848,6 +892,8 @@
         // quiet update should stop making noise
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
+        assertTrue(r.isInterruptive());
+        assertFalse(s.isInterruptive());
     }
 
     @Test
@@ -864,6 +910,7 @@
 
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
@@ -874,6 +921,7 @@
 
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
@@ -906,6 +954,7 @@
 
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
+        assertFalse(r.isInterruptive());
     }
 
     @Test
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3c371e5..9be9f3f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -990,6 +990,25 @@
         }
 
         @Override
+        public void reportInterruptiveNotification(String packageName, String channelId,
+                int userId) {
+            if (packageName == null || channelId == null) {
+                Slog.w(TAG, "Event reported without a package name or a channel ID");
+                return;
+            }
+
+            UsageEvents.Event event = new UsageEvents.Event();
+            event.mPackage = packageName.intern();
+            event.mNotificationChannelId = channelId.intern();
+
+            // This will later be converted to system time.
+            event.mTimeStamp = SystemClock.elapsedRealtime();
+
+            event.mEventType = Event.NOTIFICATION_INTERRUPTION;
+            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+        }
+
+        @Override
         public void reportShortcutUsage(String packageName, String shortcutId, int userId) {
             if (packageName == null || shortcutId == null) {
                 Slog.w(TAG, "Event reported without a package name or a shortcut ID");
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 836eb31..d974282 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -759,6 +759,8 @@
                 return "NOTIFICATION_SEEN";
             case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
                 return "STANDBY_BUCKET_CHANGED";
+            case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+                return "NOTIFICATION_INTERRUPTION";
             default:
                 return "UNKNOWN";
         }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index fb52ff7..4f78c4c 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3380,7 +3380,7 @@
          * on the given subscriptionId
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()}
+         * carrier identity {@link TelephonyManager#getSimCarrierId()}
          * while your app is running. You can also use a {@link JobService} to ensure your app
          * is notified of changes to the {@link Uri} even when it is not running.
          * Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -3396,14 +3396,14 @@
 
         /**
          * A user facing carrier name.
-         * @see TelephonyManager#getAndroidCarrierNameForSubscription()
+         * @see TelephonyManager#getSimCarrierIdName()
          * <P>Type: TEXT </P>
          */
         public static final String CARRIER_NAME = "carrier_name";
 
         /**
          * A unique carrier id
-         * @see TelephonyManager#getAndroidCarrierIdForSubscription()
+         * @see TelephonyManager#getSimCarrierId()
          * <P>Type: INTEGER </P>
          */
         public static final String CARRIER_ID = "carrier_id";
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4a61437..ef66ed7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -25,6 +25,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.BroadcastOptions;
@@ -42,7 +43,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.util.DisplayMetrics;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -59,9 +59,6 @@
 /**
  * SubscriptionManager is the application interface to SubscriptionController
  * and provides information about the current Telephony Subscriptions.
- * <p>
- * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise
- * specified.
  */
 @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
 public class SubscriptionManager {
@@ -612,6 +609,8 @@
      * @param listener an instance of {@link OnSubscriptionsChangedListener} with
      *                 onSubscriptionsChanged overridden.
      */
+    // TODO(b/70041899): Find a way to extend this to carrier-privileged apps.
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
         String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (DBG) {
@@ -660,9 +659,15 @@
     /**
      * Get the active SubscriptionInfo with the input subId.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
      * @param subId The unique SubscriptionInfo key in database.
      * @return SubscriptionInfo, maybe null if its not active.
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
         if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
         if (!isValidSubscriptionId(subId)) {
@@ -716,9 +721,16 @@
 
     /**
      * Get the active SubscriptionInfo associated with the slotIndex
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
      * @param slotIndex the slot which the subscription is inserted
      * @return SubscriptionInfo, maybe null if its not active
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
         if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex);
         if (!isValidSlotIndex(slotIndex)) {
@@ -770,6 +782,11 @@
      * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
      * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, only records accessible
+     * to the calling app are returned.
+     *
      * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
      * <ul>
      * <li>
@@ -786,6 +803,8 @@
      * </li>
      * </ul>
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
         List<SubscriptionInfo> result = null;
 
@@ -928,10 +947,18 @@
     }
 
     /**
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, the count will include
+     * only those subscriptions accessible to the caller.
+     *
      * @return the current number of active subscriptions. There is no guarantee the value
      * returned by this method will be the same as the length of the list returned by
      * {@link #getActiveSubscriptionInfoList}.
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public int getActiveSubscriptionInfoCount() {
         int result = 0;
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index aa76e9d..22795b1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,6 +23,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -53,7 +54,6 @@
 import android.telephony.ims.aidl.IImsMmTelFeature;
 import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
-import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
@@ -1082,7 +1082,7 @@
 
     /**
      * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
-     * the updated carrier id {@link TelephonyManager#getAndroidCarrierIdForSubscription()} of
+     * the updated carrier id {@link TelephonyManager#getSimCarrierId()} of
      * the current subscription.
      * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
      * the carrier cannot be identified.
@@ -1092,7 +1092,7 @@
     /**
      * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
      * indicates the updated carrier name of the current subscription.
-     * {@see TelephonyManager#getSubscriptionCarrierName()}
+     * {@see TelephonyManager#getSimCarrierIdName()}
      * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID},
      * usually the brand name of the subsidiary (e.g. T-Mobile).
      */
@@ -1114,7 +1114,11 @@
      * Returns the software version number for the device, for example,
      * the IMEI/SV for GSM phones. Return null if the software version is
      * not available.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getDeviceSoftwareVersion() {
         return getDeviceSoftwareVersion(getSlotIndex());
@@ -1146,10 +1150,14 @@
      * Returns the unique device ID, for example, the IMEI for GSM and the MEID
      * or ESN for CDMA phones. Return null if device ID is not available.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
      * MEID for CDMA.
      */
     @Deprecated
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getDeviceId() {
         try {
@@ -1168,12 +1176,16 @@
      * Returns the unique device ID of a subscription, for example, the IMEI for
      * GSM and the MEID for CDMA phones. Return null if device ID is not available.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @param slotIndex of which deviceID is returned
      *
      * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
      * MEID for CDMA.
      */
     @Deprecated
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getDeviceId(int slotIndex) {
         // FIXME this assumes phoneId == slotIndex
@@ -1192,7 +1204,11 @@
     /**
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getImei() {
         return getImei(getSlotIndex());
@@ -1202,8 +1218,12 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @param slotIndex of which IMEI is returned
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -1220,7 +1240,11 @@
 
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getMeid() {
         return getMeid(getSlotIndex());
@@ -1229,8 +1253,12 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @param slotIndex of which MEID is returned
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getMeid(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -1247,10 +1275,11 @@
 
     /**
      * Returns the Network Access Identifier (NAI). Return null if NAI is not available.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getNai() {
         return getNaiBySubscriberId(getSubId());
@@ -1751,6 +1780,7 @@
      * @see #createForSubscriptionId(int)
      * @see #createForPhoneAccountHandle(PhoneAccountHandle)
      */
+    // TODO(b/73136824, b/70041899): Permit carrier-privileged callers as well.
     @WorkerThread
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public PersistableBundle getCarrierConfig() {
@@ -1949,6 +1979,9 @@
      * If this object has been created with {@link #createForSubscriptionId}, applies to the given
      * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @return the network type
      *
      * @see #NETWORK_TYPE_UNKNOWN
@@ -1968,6 +2001,7 @@
      * @see #NETWORK_TYPE_EHRPD
      * @see #NETWORK_TYPE_HSPAP
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public int getDataNetworkType() {
         return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
@@ -2002,7 +2036,11 @@
 
     /**
      * Returns the NETWORK_TYPE_xxxx for voice
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public int getVoiceNetworkType() {
         return getVoiceNetworkType(getSubId());
@@ -2588,7 +2626,11 @@
     /**
      * Returns the serial number of the SIM, if applicable. Return null if it is
      * unavailable.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getSimSerialNumber() {
          return getSimSerialNumber(getSubId());
@@ -2713,7 +2755,11 @@
     /**
      * Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
      * Return null if it is unavailable.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getSubscriberId() {
         return getSubscriberId(getSubId());
@@ -2877,7 +2923,11 @@
     /**
      * Returns the Group Identifier Level1 for a GSM phone.
      * Return null if it is unavailable.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getGroupIdLevel1() {
         try {
@@ -2918,9 +2968,15 @@
     /**
      * Returns the phone number string for line 1, for example, the MSISDN
      * for a GSM phone. Return null if it is unavailable.
-     * <p>
-     * The default SMS app can also use this.
+     *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE},
+     *     {@link android.Manifest.permission#READ_SMS READ_SMS},
+     *     {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
+     *     that the caller is the default SMS app,
+     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_SMS,
@@ -2975,8 +3031,7 @@
      * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
      * value.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
@@ -2992,8 +3047,7 @@
      * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
      * value.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId the subscriber that the alphatag and dialing number belongs to.
      * @param alphaTag alpha-tagging of the dailing nubmer
@@ -3112,7 +3166,11 @@
 
     /**
      * Returns the voice mail number. Return null if it is unavailable.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getVoiceMailNumber() {
         return getVoiceMailNumber(getSubId());
@@ -3173,8 +3231,7 @@
     /**
      * Sets the voice mail number.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
@@ -3186,8 +3243,7 @@
     /**
      * Sets the voicemail number for the given subscriber.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription id.
      * @param alphaTag The alpha tag to display.
@@ -3208,9 +3264,9 @@
     /**
      * Enables or disables the visual voicemail client for a phone account.
      *
-     * <p>Requires that the calling app is the default dialer, or has carrier privileges, or
-     * has permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app is the default dialer, or has carrier privileges (see
+     * {@link #hasCarrierPrivileges}), or has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
      *
      * @param phoneAccountHandle the phone account to change the client state
      * @param enabled the new state of the client
@@ -3273,11 +3329,15 @@
      * to the TelephonyManager. Returns {@code null} when there is no package responsible for
      * processing visual voicemail for the subscription.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @see #createForSubscriptionId(int)
      * @see #createForPhoneAccountHandle(PhoneAccountHandle)
      * @see VisualVoicemailService
      */
     @Nullable
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getVisualVoicemailPackageName() {
         try {
@@ -3520,15 +3580,14 @@
       * Sets the voice activation state
       *
       * <p>Requires Permission:
-      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-      * Or the calling app has carrier privileges.
+      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+      * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
       *
       * @param activationState The voice activation state
       * @see #SIM_ACTIVATION_STATE_UNKNOWN
       * @see #SIM_ACTIVATION_STATE_ACTIVATING
       * @see #SIM_ACTIVATION_STATE_ACTIVATED
       * @see #SIM_ACTIVATION_STATE_DEACTIVATED
-      * @see #hasCarrierPrivileges
       * @hide
       */
     @SystemApi
@@ -3541,8 +3600,8 @@
      * Sets the voice activation state for the given subscriber.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+     * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription id.
      * @param activationState The voice activation state of the given subscriber.
@@ -3550,7 +3609,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATING
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -3568,8 +3626,8 @@
      * Sets the data activation state
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+     * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param activationState The data activation state
      * @see #SIM_ACTIVATION_STATE_UNKNOWN
@@ -3577,7 +3635,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @SystemApi
@@ -3590,8 +3647,8 @@
      * Sets the data activation state for the given subscriber.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+     * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription id.
      * @param activationState The data activation state of the given subscriber.
@@ -3600,7 +3657,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -3618,15 +3674,14 @@
      * Returns the voice activation state
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @return voiceActivationState
      * @see #SIM_ACTIVATION_STATE_UNKNOWN
      * @see #SIM_ACTIVATION_STATE_ACTIVATING
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @SystemApi
@@ -3639,8 +3694,8 @@
      * Returns the voice activation state for the given subscriber.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription id.
      *
@@ -3649,7 +3704,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATING
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3668,8 +3722,8 @@
      * Returns the data activation state
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @return dataActivationState for the given subscriber
      * @see #SIM_ACTIVATION_STATE_UNKNOWN
@@ -3677,7 +3731,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @SystemApi
@@ -3690,8 +3743,8 @@
      * Returns the data activation state for the given subscriber.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
-     * Or the calling app has carrier privileges.
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription id.
      *
@@ -3701,7 +3754,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3749,7 +3801,11 @@
     /**
      * Retrieves the alphabetic identifier associated with the voice
      * mail number.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getVoiceMailAlphaTag() {
         return getVoiceMailAlphaTag(getSubId());
@@ -3778,9 +3834,8 @@
     }
 
     /**
-     * Send the special dialer code. The IPC caller must be the current default dialer or has
-     * carrier privileges.
-     * @see #hasCarrierPrivileges
+     * Send the special dialer code. The IPC caller must be the current default dialer or have
+     * carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param inputCode The special dialer code to send
      *
@@ -4304,8 +4359,8 @@
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return an IccOpenLogicalChannelResponse object.
@@ -4322,8 +4377,8 @@
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @param p2 P2 parameter (described in ISO 7816-4).
@@ -4339,8 +4394,8 @@
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param AID Application id. See ETSI 102.221 and 101.220.
@@ -4365,8 +4420,8 @@
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
@@ -4382,8 +4437,8 @@
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param channel is the channel id to be closed as retruned by a successful
@@ -4408,8 +4463,8 @@
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
@@ -4435,8 +4490,8 @@
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param channel is the channel id to be closed as returned by a successful
@@ -4471,8 +4526,8 @@
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -4496,8 +4551,8 @@
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param cla Class of the APDU command.
@@ -4528,8 +4583,8 @@
      * Returns the response APDU for a command APDU sent through SIM_IO.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param fileID
      * @param command
@@ -4548,8 +4603,8 @@
      * Returns the response APDU for a command APDU sent through SIM_IO.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param fileID
@@ -4577,8 +4632,8 @@
      * Send ENVELOPE to the SIM and return the response.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param content String containing SAT/USAT response in hexadecimal
      *                format starting with command tag. See TS 102 223 for
@@ -4595,8 +4650,8 @@
      * Send ENVELOPE to the SIM and return the response.
      *
      * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param content String containing SAT/USAT response in hexadecimal
@@ -4621,10 +4676,10 @@
     /**
      * Read one of the NV items defined in com.android.internal.telephony.RadioNVItems.
      * Used for device configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param itemID the ID of the item to read.
      * @return the NV item as a String, or null on any failure.
@@ -4647,10 +4702,10 @@
     /**
      * Write one of the NV items defined in com.android.internal.telephony.RadioNVItems.
      * Used for device configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param itemID the ID of the item to read.
      * @param itemValue the value to write, as a String.
@@ -4674,10 +4729,10 @@
     /**
      * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
      * Used for device configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param preferredRoamingList byte array containing the new PRL.
      * @return true on success; false on any failure.
@@ -4701,10 +4756,10 @@
      * Perform the specified type of NV config reset. The radio will be taken offline
      * and the device must be rebooted after the operation. Used for device
      * configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
      * @return true on success; false on any failure.
@@ -5052,8 +5107,8 @@
      * Returns the response of authentication for the default subscription.
      * Returns null if the authentication hasn't been successful
      *
-     * <p>Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE
-     * permission.
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
      * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
@@ -5061,9 +5116,10 @@
      * @param data authentication challenge data, base64 encoded.
      * See 3GPP TS 31.102 7.1.2 for more details.
      * @return the response of authentication, or null if not available
-     *
-     * @see #hasCarrierPrivileges
      */
+    // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
+    // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
+    // it's not public API.
     public String getIccAuthentication(int appType, int authType, String data) {
         return getIccAuthentication(getSubId(), appType, authType, data);
     }
@@ -5072,7 +5128,7 @@
      * Returns the response of USIM Authentication for specified subId.
      * Returns null if the authentication hasn't been successful
      *
-     * <p>Requires that the calling app has carrier privileges.
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId subscription ID used for authentication
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
@@ -5081,8 +5137,6 @@
      * @param data authentication challenge data, base64 encoded.
      * See 3GPP TS 31.102 7.1.2 for more details.
      * @return the response of authentication, or null if not available
-     *
-     * @see #hasCarrierPrivileges
      * @hide
      */
     public String getIccAuthentication(int subId, int appType, int authType, String data) {
@@ -5103,8 +5157,12 @@
      * Returns an array of Forbidden PLMNs from the USIM App
      * Returns null if the query fails.
      *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @return an array of forbidden PLMNs or null if not available
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String[] getForbiddenPlmns() {
       return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
@@ -5310,10 +5368,10 @@
     /**
      * Get the preferred network type.
      * Used for device configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @return the preferred network type, defined in RILConstants.java.
      * @hide
@@ -5333,11 +5391,12 @@
 
     /**
      * Sets the network selection mode to automatic.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setNetworkSelectionModeAutomatic() {
         try {
@@ -5353,15 +5412,14 @@
     }
 
     /**
-     * Perform a radio scan and return the list of avialble networks.
+     * Perform a radio scan and return the list of available networks.
      *
      * The return value is a list of the OperatorInfo of the networks found. Note that this
      * scan can take a long time (sometimes minutes) to happen.
      *
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @hide
      * TODO: Add an overload that takes no args.
@@ -5385,17 +5443,16 @@
      * This method is asynchronous, so the network scan results will be returned by callback.
      * The returned NetworkScan will contain a callback method which can be used to stop the scan.
      *
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges()
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param request Contains all the RAT with bands/channels that need to be scanned.
      * @param executor The executor through which the callback should be invoked.
      * @param callback Returns network scan results or errors.
      * @return A NetworkScan obj which contains a callback which can be used to stop the scan.
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public NetworkScan requestNetworkScan(
             NetworkScanRequest request, Executor executor,
@@ -5423,10 +5480,9 @@
     /**
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param operatorNumeric the PLMN ID of the network to select.
      * @param persistSelection whether the selection will persist until reboot. If true, only allows
@@ -5434,6 +5490,7 @@
      * normal network selection next time.
      * @return true on success; false on any failure.
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
         try {
@@ -5453,10 +5510,10 @@
     /**
      * Set the preferred network type.
      * Used for device configuration by some CDMA operators.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId the id of the subscription to set the preferred network type for.
      * @param networkType the preferred network type, defined in RILConstants.java.
@@ -5480,9 +5537,7 @@
     /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
-     * <p>
-     * Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @return true on success; false on any failure.
      */
@@ -5493,9 +5548,7 @@
     /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
-     * <p>
-     * Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @return true on success; false on any failure.
      * @hide
@@ -5585,8 +5638,7 @@
      * brand value input. To unset the value, the same function should be
      * called with a null brand value.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
@@ -5603,8 +5655,7 @@
      * brand value input. To unset the value, the same function should be
      * called with a null brand value.
      *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
      * @param brand The brand name to display/set.
@@ -6258,15 +6309,15 @@
      * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *
      * <p>Requires Permission:
-     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
-     *     calling app has carrier privileges.
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param enable Whether to enable mobile data.
      *
-     * @see #hasCarrierPrivileges
      * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead.
      */
     @Deprecated
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setDataEnabled(boolean enable) {
         setUserMobileDataEnabled(enable);
@@ -6303,7 +6354,7 @@
      * <p>Requires one of the following permissions:
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
-     * calling app has carrier privileges.
+     * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * <p>Note that this does not take into account any data restrictions that may be present on the
      * calling app. Such restrictions may be inspected with
@@ -6311,7 +6362,6 @@
      *
      * @return true if mobile data is enabled.
      *
-     * @see #hasCarrierPrivileges
      * @deprecated use {@link #isUserMobileDataEnabled()} instead.
      */
     @Deprecated
@@ -7082,7 +7132,11 @@
 
     /**
      * Returns the current {@link ServiceState} information.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public ServiceState getServiceState() {
         return getServiceStateForSubscriber(getSubId());
@@ -7128,14 +7182,14 @@
     /**
      * Sets the per-account voicemail ringtone.
      *
-     * <p>Requires that the calling app is the default dialer, or has carrier privileges, or has
-     * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     * <p>Requires that the calling app is the default dialer, or has carrier privileges (see
+     * {@link #hasCarrierPrivileges}, or has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
      *
      * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
      * voicemail ringtone.
      * @param uri The URI for the ringtone to play when receiving a voicemail from a specific
      * PhoneAccount.
-     * @see #hasCarrierPrivileges
      *
      * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
      * instead.
@@ -7173,14 +7227,14 @@
     /**
      * Sets the per-account preference whether vibration is enabled for voicemail notifications.
      *
-     * <p>Requires that the calling app is the default dialer, or has carrier privileges, or has
-     * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     * <p>Requires that the calling app is the default dialer, or has carrier privileges (see
+     * {@link #hasCarrierPrivileges}, or has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
      *
      * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
      * voicemail vibration setting.
      * @param enabled Whether to enable or disable vibration for voicemail notifications from a
      * specific PhoneAccount.
-     * @see #hasCarrierPrivileges
      *
      * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
      * instead.
@@ -7201,8 +7255,8 @@
     /**
      * Returns carrier id of the current subscription.
      * <p>To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
-     * carrier with a canonical integer a.k.a. android carrier id. The Android carrier ID is an
-     * Android platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
+     * carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android
+     * platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
      * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
      *
      * <p>Apps which have carrier-specific configurations or business logic can use the carrier id
@@ -7211,7 +7265,7 @@
      * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
      * subscription is unavailable or the carrier cannot be identified.
      */
-    public int getAndroidCarrierIdForSubscription() {
+    public int getSimCarrierId() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
@@ -7224,18 +7278,18 @@
     }
 
     /**
-     * Returns carrier name of the current subscription.
-     * <p>Carrier name is a user-facing name of carrier id
-     * {@link #getAndroidCarrierIdForSubscription()}, usually the brand name of the subsidiary
+     * Returns carrier id name of the current subscription.
+     * <p>Carrier id name is a user-facing name of carrier id
+     * {@link #getSimCarrierId()}, usually the brand name of the subsidiary
      * (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but
      * should have a single carrier name. Carrier name is not a canonical identity,
-     * use {@link #getAndroidCarrierIdForSubscription()} instead.
+     * use {@link #getSimCarrierId()} instead.
      * <p>The returned carrier name is unlocalized.
      *
      * @return Carrier name of the current subscription. Return {@code null} if the subscription is
      * unavailable or the carrier cannot be identified.
      */
-    public CharSequence getAndroidCarrierNameForSubscription() {
+    public CharSequence getSimCarrierIdName() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
@@ -7601,12 +7655,10 @@
      * Otherwise, it applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *
      * <p>Requires Permission:
-     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
-     *     calling app has carrier privileges.
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}.
      *
      * @param enable Whether to enable mobile data.
-     *
-     * @see #hasCarrierPrivileges
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setUserMobileDataEnabled(boolean enable) {
@@ -7624,15 +7676,13 @@
      * <p>Requires one of the following permissions:
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
-     * calling app has carrier privileges.
+     * calling app has carrier privileges (see {@link #hasCarrierPrivileges}.
      *
      * <p>Note that this does not take into account any data restrictions that may be present on the
      * calling app. Such restrictions may be inspected with
      * {@link ConnectivityManager#getRestrictBackgroundStatus}.
      *
      * @return true if mobile data is enabled.
-     *
-     * @see #hasCarrierPrivileges
      */
     @RequiresPermission(anyOf = {
             android.Manifest.permission.ACCESS_NETWORK_STATE,
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a941a56..4002d3c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1358,10 +1358,10 @@
 
     /**
      * Returns carrier name of the given subscription.
-     * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId(int)},
+     * <p>Carrier name is a user-facing name of carrier id {@link #getSimCarrierId(int)},
      * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure
      * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name.
-     * Carrier name is not canonical identity, use {@link #getSubscriptionCarrierId(int)} instead.
+     * Carrier name is not canonical identity, use {@link #getSimCarrierId(int)} instead.
      * <p>Returned carrier name is unlocalized.
      *
      * @return Carrier name of given subscription id. return {@code null} if subscription is
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index da8471f..a182f2b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -26,7 +26,8 @@
 import android.telephony.TelephonyManager;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.ITelephony;
+
+import java.util.function.Supplier;
 
 /** Utility class for Telephony permission enforcement. */
 public final class TelephonyPermissions {
@@ -34,6 +35,9 @@
 
     private static final boolean DBG = false;
 
+    private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
+            ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+
     private TelephonyPermissions() {}
 
     /**
@@ -41,8 +45,8 @@
      *
      * <p>This method behaves in one of the following ways:
      * <ul>
-     *   <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
-     *       READ_PHONE_STATE runtime permission.
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
      *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
      *       apps which support runtime permissions, if the caller does not currently have any of
      *       these permissions.
@@ -51,20 +55,30 @@
      *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
      *       so we return false to indicate that the calling function should return dummy data.
      * </ul>
+     *
+     * <p>Note: for simplicity, this method always returns false for callers using legacy
+     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+     * devices.
+     *
+     * @param subId the subId of the relevant subscription; used to check carrier privileges. May be
+     *              {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} to skip this check for cases
+     *              where it isn't relevant (hidden APIs, or APIs which are otherwise okay to leave
+     *              inaccesible to carrier-privileged apps).
      */
     public static boolean checkCallingOrSelfReadPhoneState(
-            Context context, String callingPackage, String message) {
-        return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(),
+            Context context, int subId, String callingPackage, String message) {
+        return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
                 callingPackage, message);
     }
 
     /**
      * Check whether the app with the given pid/uid can read phone state.
      *
-     * <p>This method behaves in one of the following ways:
+    * <p>This method behaves in one of the following ways:
      * <ul>
-     *   <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
-     *       READ_PHONE_STATE runtime permission.
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
      *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
      *       apps which support runtime permissions, if the caller does not currently have any of
      *       these permissions.
@@ -73,9 +87,22 @@
      *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
      *       so we return false to indicate that the calling function should return dummy data.
      * </ul>
+     *
+     * <p>Note: for simplicity, this method always returns false for callers using legacy
+     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+     * devices.
      */
     public static boolean checkReadPhoneState(
-            Context context, int pid, int uid, String callingPackage, String message) {
+            Context context, int subId, int pid, int uid, String callingPackage, String message) {
+        return checkReadPhoneState(
+                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, message);
+    }
+
+    @VisibleForTesting
+    public static boolean checkReadPhoneState(
+            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+            String callingPackage, String message) {
         try {
             context.enforcePermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -83,8 +110,18 @@
             // SKIP checking for run-time permission since caller has PRIVILEGED permission
             return true;
         } catch (SecurityException privilegedPhoneStateException) {
-            context.enforcePermission(
-                    android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+            try {
+                context.enforcePermission(
+                        android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+            } catch (SecurityException phoneStateException) {
+                // If we don't have the runtime permission, but do have carrier privileges, that
+                // suffices for reading phone state.
+                if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                    enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+                    return true;
+                }
+                throw phoneStateException;
+            }
         }
 
         // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
@@ -101,14 +138,16 @@
      * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
      */
     public static boolean checkCallingOrSelfReadPhoneNumber(
-            Context context, String callingPackage, String message) {
+            Context context, int subId, String callingPackage, String message) {
         return checkReadPhoneNumber(
-                context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+                context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+                callingPackage, message);
     }
 
     @VisibleForTesting
     public static boolean checkReadPhoneNumber(
-            Context context, int pid, int uid, String callingPackage, String message) {
+            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+            String callingPackage, String message) {
         // Default SMS app can always read it.
         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) ==
@@ -121,7 +160,8 @@
 
         // First, check if we can read the phone state.
         try {
-            return checkReadPhoneState(context, pid, uid, callingPackage, message);
+            return checkReadPhoneState(
+                    context, telephonySupplier, subId, pid, uid, callingPackage, message);
         } catch (SecurityException readPhoneStateSecurityException) {
         }
         // Can be read with READ_SMS too.
@@ -186,16 +226,21 @@
     }
 
     private static void enforceCarrierPrivilege(int subId, int uid, String message) {
-        if (getCarrierPrivilegeStatus(subId, uid) !=
+        enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+    }
+
+    private static void enforceCarrierPrivilege(
+            Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
+        if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) !=
                 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
             if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
             throw new SecurityException(message);
         }
     }
 
-    private static int getCarrierPrivilegeStatus(int subId, int uid) {
-        ITelephony telephony =
-                ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+    private static int getCarrierPrivilegeStatus(
+            Supplier<ITelephony> telephonySupplier, int subId, int uid) {
+        ITelephony telephony = telephonySupplier.get();
         try {
             if (telephony != null) {
                 return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 936a1f2..4705e1d 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -189,7 +189,8 @@
     }
 
     /**
-     * @return The Location Configuration Information (LCI) as self-reported by the peer.
+     * @return The Location Configuration Information (LCI) as self-reported by the peer. The format
+     * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.10.
      * <p>
      * Note: the information is NOT validated - use with caution. Consider validating it with
      * other sources of information before using it.
@@ -207,7 +208,8 @@
     }
 
     /**
-     * @return The Location Civic report (LCR) as self-reported by the peer.
+     * @return The Location Civic report (LCR) as self-reported by the peer. The format
+     * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.13.
      * <p>
      * Note: the information is NOT validated - use with caution. Consider validating it with
      * other sources of information before using it.