Merge changes Iff142ccd,I724080ed into pi-dev

* changes:
  Multi cutout: Fix IME navigation guard
  Multi Cutout: Fix more cutout issues
diff --git a/api/current.txt b/api/current.txt
index 050afb6..4021ffb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4265,6 +4265,7 @@
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
+    method public static java.lang.String getProcessName();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -5752,8 +5753,15 @@
     field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0
     field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1
     field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2
-    field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
-    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_AMBIENT = 128; // 0x80
+    field public static final int SUPPRESSED_EFFECT_BADGE = 64; // 0x40
+    field public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 4; // 0x4
+    field public static final int SUPPRESSED_EFFECT_LIGHTS = 8; // 0x8
+    field public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 256; // 0x100
+    field public static final int SUPPRESSED_EFFECT_PEEK = 16; // 0x10
+    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_STATUS_BAR = 32; // 0x20
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -7263,6 +7271,7 @@
     method public android.net.Uri mapIntentToUri(android.content.Intent);
     method public void pinSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
     method public void unpinSlice(android.net.Uri);
+    field public static final java.lang.String CATEGORY_SLICE = "android.app.slice.category.SLICE";
     field public static final java.lang.String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
   }
 
@@ -16426,8 +16435,8 @@
   }
 
   public final class SessionConfiguration {
-    ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler);
-    method public android.os.Handler getHandler();
+    ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
+    method public java.util.concurrent.Executor getExecutor();
     method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
     method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
     method public android.hardware.camera2.CaptureRequest getSessionParameters();
@@ -23249,6 +23258,7 @@
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
     field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
+    field public static final int HEVCProfileMainStill = 4; // 0x4
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelHP = 4; // 0x4
@@ -24042,13 +24052,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;
@@ -24094,6 +24104,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;
@@ -24341,7 +24358,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);
@@ -24367,33 +24383,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
@@ -24443,7 +24461,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);
@@ -27581,17 +27599,17 @@
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
-    field public static final int TYPE_BLUETOOTH = 7; // 0x7
-    field public static final int TYPE_DUMMY = 8; // 0x8
-    field public static final int TYPE_ETHERNET = 9; // 0x9
-    field public static final int TYPE_MOBILE = 0; // 0x0
-    field public static final int TYPE_MOBILE_DUN = 4; // 0x4
+    field public static final deprecated int TYPE_BLUETOOTH = 7; // 0x7
+    field public static final deprecated int TYPE_DUMMY = 8; // 0x8
+    field public static final deprecated int TYPE_ETHERNET = 9; // 0x9
+    field public static final deprecated int TYPE_MOBILE = 0; // 0x0
+    field public static final deprecated int TYPE_MOBILE_DUN = 4; // 0x4
     field public static final deprecated int TYPE_MOBILE_HIPRI = 5; // 0x5
     field public static final deprecated int TYPE_MOBILE_MMS = 2; // 0x2
     field public static final deprecated int TYPE_MOBILE_SUPL = 3; // 0x3
-    field public static final int TYPE_VPN = 17; // 0x11
-    field public static final int TYPE_WIFI = 1; // 0x1
-    field public static final int TYPE_WIMAX = 6; // 0x6
+    field public static final deprecated int TYPE_VPN = 17; // 0x11
+    field public static final deprecated int TYPE_WIFI = 1; // 0x1
+    field public static final deprecated int TYPE_WIMAX = 6; // 0x6
   }
 
   public static class ConnectivityManager.NetworkCallback {
@@ -27868,16 +27886,16 @@
     method public int describeContents();
     method public android.net.NetworkInfo.DetailedState getDetailedState();
     method public java.lang.String getExtraInfo();
-    method public java.lang.String getReason();
-    method public android.net.NetworkInfo.State getState();
+    method public deprecated java.lang.String getReason();
+    method public deprecated android.net.NetworkInfo.State getState();
     method public int getSubtype();
     method public java.lang.String getSubtypeName();
-    method public int getType();
-    method public java.lang.String getTypeName();
-    method public boolean isAvailable();
+    method public deprecated int getType();
+    method public deprecated java.lang.String getTypeName();
+    method public deprecated boolean isAvailable();
     method public boolean isConnected();
-    method public boolean isConnectedOrConnecting();
-    method public boolean isFailover();
+    method public deprecated boolean isConnectedOrConnecting();
+    method public deprecated boolean isFailover();
     method public deprecated boolean isRoaming();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
@@ -40001,8 +40019,8 @@
     field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
     field public static final int REASON_USER_STOPPED = 6; // 0x6
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
-    field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
-    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
   }
 
   public static class NotificationListenerService.Ranking {
@@ -42140,11 +42158,9 @@
 package android.telephony {
 
   public final class AccessNetworkConstants {
-    ctor public AccessNetworkConstants();
   }
 
   public static final class AccessNetworkConstants.AccessNetworkType {
-    ctor public AccessNetworkConstants.AccessNetworkType();
     field public static final int CDMA2000 = 4; // 0x4
     field public static final int EUTRAN = 3; // 0x3
     field public static final int GERAN = 1; // 0x1
@@ -42154,7 +42170,6 @@
   }
 
   public static final class AccessNetworkConstants.EutranBand {
-    ctor public AccessNetworkConstants.EutranBand();
     field public static final int BAND_1 = 1; // 0x1
     field public static final int BAND_10 = 10; // 0xa
     field public static final int BAND_11 = 11; // 0xb
@@ -42206,7 +42221,6 @@
   }
 
   public static final class AccessNetworkConstants.GeranBand {
-    ctor public AccessNetworkConstants.GeranBand();
     field public static final int BAND_450 = 3; // 0x3
     field public static final int BAND_480 = 4; // 0x4
     field public static final int BAND_710 = 5; // 0x5
@@ -42224,7 +42238,6 @@
   }
 
   public static final class AccessNetworkConstants.UtranBand {
-    ctor public AccessNetworkConstants.UtranBand();
     field public static final int BAND_1 = 1; // 0x1
     field public static final int BAND_10 = 10; // 0xa
     field public static final int BAND_11 = 11; // 0xb
@@ -42665,7 +42678,8 @@
   }
 
   public class NetworkScan {
-    method public void stop() throws android.os.RemoteException;
+    method public deprecated void stop() throws android.os.RemoteException;
+    method public void stopScan();
     field public static final int ERROR_INTERRUPTED = 10002; // 0x2712
     field public static final int ERROR_INVALID_SCAN = 2; // 0x2
     field public static final int ERROR_INVALID_SCANID = 10001; // 0x2711
@@ -43067,8 +43081,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();
@@ -43099,6 +43111,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();
@@ -43130,7 +43144,8 @@
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
-    method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
+    method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
+    method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
     method public void sendDialerSpecialCode(java.lang.String);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
@@ -51031,6 +51046,77 @@
 
 package android.view.textclassifier {
 
+  public abstract class Logger {
+    ctor public Logger(android.view.textclassifier.Logger.Config);
+    method public java.text.BreakIterator getTokenIterator(java.util.Locale);
+    method public boolean isSmartSelection(java.lang.String);
+    method public final void logSelectionActionEvent(int, int, int);
+    method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
+    method public final void logSelectionModifiedEvent(int, int);
+    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
+    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
+    method public final void logSelectionStartedEvent(int, int);
+    method public abstract void writeEvent(android.view.textclassifier.SelectionEvent);
+    field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
+    field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
+    field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
+    field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
+    field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+    field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
+    field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
+    field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
+    field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
+    field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+    field public static final java.lang.String WIDGET_WEBVIEW = "webview";
+  }
+
+  public static final class Logger.Config {
+    ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
+    method public java.lang.String getPackageName();
+    method public java.lang.String getWidgetType();
+    method public java.lang.String getWidgetVersion();
+  }
+
+  public final class SelectionEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getDurationSincePreviousEvent();
+    method public long getDurationSinceSessionStart();
+    method public int getEnd();
+    method public java.lang.String getEntityType();
+    method public int getEventIndex();
+    method public long getEventTime();
+    method public int getEventType();
+    method public int getInvocationMethod();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getSessionId();
+    method public java.lang.String getSignature();
+    method public int getSmartEnd();
+    method public int getSmartStart();
+    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
+    field public static final int ACTION_DRAG = 106; // 0x6a
+    field public static final int ACTION_OTHER = 108; // 0x6c
+    field public static final int ACTION_OVERTYPE = 100; // 0x64
+    field public static final int ACTION_PASTE = 102; // 0x66
+    field public static final int ACTION_RESET = 201; // 0xc9
+    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
+    field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
+    field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
+    field public static final int INVOCATION_LINK = 2; // 0x2
+    field public static final int INVOCATION_MANUAL = 1; // 0x1
+  }
+
   public final class TextClassification implements android.os.Parcelable {
     method public int describeContents();
     method public float getConfidenceScore(java.lang.String);
@@ -51087,7 +51173,7 @@
     method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
     method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
     method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
-    method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+    method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config);
     method public default int getMaxGenerateLinksTextLength();
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
@@ -51200,78 +51286,6 @@
 
 }
 
-package android.view.textclassifier.logging {
-
-  public abstract class Logger {
-    ctor public Logger(android.view.textclassifier.logging.Logger.Config);
-    method public java.text.BreakIterator getTokenIterator(java.util.Locale);
-    method public boolean isSmartSelection(java.lang.String);
-    method public final void logSelectionActionEvent(int, int, int);
-    method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
-    method public final void logSelectionModifiedEvent(int, int);
-    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
-    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
-    method public final void logSelectionStartedEvent(int, int);
-    method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
-    field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
-    field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
-    field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
-    field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
-    field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
-    field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
-    field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
-    field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
-    field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
-    field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
-    field public static final java.lang.String WIDGET_WEBVIEW = "webview";
-  }
-
-  public static final class Logger.Config {
-    ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
-    method public java.lang.String getPackageName();
-    method public java.lang.String getWidgetType();
-    method public java.lang.String getWidgetVersion();
-  }
-
-  public final class SelectionEvent {
-    method public long getDurationSincePreviousEvent();
-    method public long getDurationSinceSessionStart();
-    method public int getEnd();
-    method public java.lang.String getEntityType();
-    method public int getEventIndex();
-    method public long getEventTime();
-    method public int getEventType();
-    method public int getInvocationMethod();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getSessionId();
-    method public java.lang.String getSignature();
-    method public int getSmartEnd();
-    method public int getSmartStart();
-    method public int getStart();
-    method public java.lang.String getWidgetType();
-    method public java.lang.String getWidgetVersion();
-    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
-    field public static final int ACTION_DRAG = 106; // 0x6a
-    field public static final int ACTION_OTHER = 108; // 0x6c
-    field public static final int ACTION_OVERTYPE = 100; // 0x64
-    field public static final int ACTION_PASTE = 102; // 0x66
-    field public static final int ACTION_RESET = 201; // 0xc9
-    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 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
-    field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
-    field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
-    field public static final int INVOCATION_LINK = 2; // 0x2
-    field public static final int INVOCATION_MANUAL = 1; // 0x1
-  }
-
-}
-
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -53391,6 +53405,9 @@
   public final class Magnifier {
     ctor public Magnifier(android.view.View);
     method public void dismiss();
+    method public int getHeight();
+    method public int getWidth();
+    method public float getZoom();
     method public void show(float, float);
     method public void update();
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 048acbd..43425cb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -377,6 +377,7 @@
     method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method public boolean setDataFetchOperation(long, android.app.PendingIntent);
     field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+    field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
     field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
     field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
     field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
@@ -716,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
   }
@@ -840,6 +843,7 @@
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field public static final java.lang.String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
     field public static final java.lang.String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
     field public static final java.lang.String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
     field public static final java.lang.String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
@@ -3612,6 +3616,11 @@
 
 package android.os {
 
+  public class BatteryManager {
+    field public static final java.lang.String EXTRA_EVENTS = "android.os.extra.EVENTS";
+    field public static final java.lang.String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
+  }
+
   public final class ConfigUpdate {
     field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
     field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
@@ -4697,9 +4706,11 @@
 
   public abstract class TextClassifierService extends android.app.Service {
     ctor public TextClassifierService();
+    method public final android.view.textclassifier.TextClassifier getLocalTextClassifier();
     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";
   }
@@ -4995,7 +5006,6 @@
 package android.telephony {
 
   public static final class AccessNetworkConstants.TransportType {
-    ctor public AccessNetworkConstants.TransportType();
     field public static final int WLAN = 2; // 0x2
     field public static final int WWAN = 1; // 0x1
   }
@@ -5495,6 +5505,9 @@
   }
 
   public final class ImsCallProfile implements android.os.Parcelable {
+    ctor public ImsCallProfile();
+    ctor public ImsCallProfile(int, int);
+    ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
     method public int describeContents();
     method public java.lang.String getCallExtra(java.lang.String);
     method public java.lang.String getCallExtra(java.lang.String, java.lang.String);
@@ -5518,6 +5531,7 @@
     method public void setCallExtraInt(java.lang.String, int);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
+    method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2
     field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
@@ -5855,6 +5869,7 @@
   }
 
   public final class ImsStreamMediaProfile implements android.os.Parcelable {
+    ctor public ImsStreamMediaProfile(int, int, int, int, int);
     method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
     method public int describeContents();
     method public int getAudioDirection();
@@ -6662,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/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 9513cc5..3b0cd34 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -21,6 +21,7 @@
 #include "guardrail/StatsdStats.h"
 #include "puller_util.h"
 #include "stats_log_util.h"
+#include "StatsPullerManagerImpl.h"
 
 namespace android {
 namespace os {
@@ -34,11 +35,7 @@
 // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
 StatsPuller::StatsPuller(const int tagId)
     : mTagId(tagId) {
-    if (StatsdStats::kPullerCooldownMap.find(tagId) == StatsdStats::kPullerCooldownMap.end()) {
-        mCoolDownSec = StatsdStats::kDefaultPullerCooldown;
-    } else {
-        mCoolDownSec = StatsdStats::kPullerCooldownMap[tagId];
-    }
+    mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec;
     VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec);
 }
 
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index d626d90..c6c4d13 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -91,18 +91,6 @@
 const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
 const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
 
-std::map<int, long> StatsdStats::kPullerCooldownMap = {
-        {android::util::KERNEL_WAKELOCK, 1},
-        {android::util::WIFI_BYTES_TRANSFER, 1},
-        {android::util::MOBILE_BYTES_TRANSFER, 1},
-        {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1},
-        {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1},
-        {android::util::SUBSYSTEM_SLEEP_STATE, 1},
-        {android::util::CPU_TIME_PER_FREQ, 1},
-        {android::util::CPU_TIME_PER_UID, 1},
-        {android::util::CPU_TIME_PER_UID_FREQ, 1},
-};
-
 // TODO: add stats for pulled atoms.
 StatsdStats::StatsdStats() {
     mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index c3f4013..d05c91b 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -111,13 +111,6 @@
     /* Min period between two checks of byte size per config key in nanoseconds. */
     static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
 
-    // Default minimum interval between pulls for an atom. Pullers can return cached values if
-    // another pull request happens within this interval.
-    static std::map<int, long> kPullerCooldownMap;
-
-    // Default cooldown time for a puller
-    static const long kDefaultPullerCooldown = 1;
-
     // Maximum age (30 days) that files on disk can exist in seconds.
     static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 0dd3f70..bc09683 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -126,6 +126,13 @@
 sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
         const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
     std::lock_guard<std::mutex> lock(mMutex);
+    if (mAggregationType == DurationMetric_AggregationType_SUM) {
+        if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
+            ALOGW("invalid alert for SUM: threshold (%f) > possible recordable value (%d x %lld)",
+                  alert.trigger_if_sum_gt(), alert.num_buckets(), (long long)mBucketSizeNs);
+            return nullptr;
+        }
+    }
     sp<DurationAnomalyTracker> anomalyTracker =
         new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
     if (anomalyTracker != nullptr) {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1e8aa12..1c99e2a 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -295,6 +295,7 @@
 
 message BroadcastSubscriberDetails {
   optional int64 subscriber_id = 1;
+  repeated string cookie = 2;
 }
 
 message Subscription {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 95ecf80..25d2257 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -77,6 +77,12 @@
     }
     int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
 
+    vector<String16> cookies;
+    cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
+    for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
+        cookies.push_back(String16(cookie.c_str()));
+    }
+
     auto it1 = mIntentMap.find(configKey);
     if (it1 == mIntentMap.end()) {
         ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str());
@@ -88,12 +94,13 @@
                 configKey.ToString().c_str(), (long long)subscriberId);
         return;
     }
-    sendBroadcastLocked(it2->second, configKey, subscription, dimKey);
+    sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
 }
 
 void SubscriberReporter::sendBroadcastLocked(const sp<IBinder>& intentSender,
                                              const ConfigKey& configKey,
                                              const Subscription& subscription,
+                                             const vector<String16>& cookies,
                                              const MetricDimensionKey& dimKey) const {
     VLOG("SubscriberReporter::sendBroadcastLocked called.");
     if (mStatsCompanionService == nullptr) {
@@ -101,11 +108,16 @@
         return;
     }
     mStatsCompanionService->sendSubscriberBroadcast(
-            intentSender, configKey.GetUid(), configKey.GetId(), subscription.id(),
-            subscription.rule_id(), getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
+            intentSender,
+            configKey.GetUid(),
+            configKey.GetId(),
+            subscription.id(),
+            subscription.rule_id(),
+            cookies,
+            getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
 }
 
-void getStatsDimensionsValueHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
+void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth,
                                    int prefix, vector<StatsDimensionsValue>* output) {
     size_t count = dims.size();
     while (*index < count) {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 50100df..2a7f771 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -26,6 +26,7 @@
 
 #include <mutex>
 #include <unordered_map>
+#include <vector>
 
 namespace android {
 namespace os {
@@ -102,6 +103,7 @@
     void sendBroadcastLocked(const sp<android::IBinder>& intentSender,
                              const ConfigKey& configKey,
                              const Subscription& subscription,
+                             const std::vector<String16>& cookies,
                              const MetricDimensionKey& dimKey) const;
 };
 
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index b889d1a..f134e54 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -8,6 +8,7 @@
 Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder;
 Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)Z
+Landroid/app/ActivityManager;->getMaxRecentTasksStatic()I
 Landroid/app/ActivityManager;->getService()Landroid/app/IActivityManager;
 Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton;
 Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
@@ -15,6 +16,7 @@
 Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
 Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
 Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
+Landroid/app/ActivityManager;->PROCESS_STATE_IMPORTANT_BACKGROUND:I
 Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
 Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
 Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
@@ -113,6 +115,7 @@
 Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
+Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
 Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -301,6 +304,7 @@
 Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
 Landroid/app/StatusBarManager;->expandSettingsPanel()V
 Landroid/app/StatusBarManager;->getService()Lcom/android/internal/statusbar/IStatusBarService;
+Landroid/app/TaskStackListener;-><init>()V
 Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
 Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/usage/UsageStatsManager;->mService:Landroid/app/usage/IUsageStatsManager;
@@ -335,6 +339,7 @@
 Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
 Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
+Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord;
 Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
 Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
 Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
@@ -441,6 +446,7 @@
 Landroid/content/pm/PackageUserState;-><init>()V
 Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
 Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z
+Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService;
 Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
 Landroid/content/pm/UserInfo;->id:I
 Landroid/content/pm/UserInfo;->isPrimary()Z
@@ -592,6 +598,7 @@
 Landroid/graphics/drawable/StateListDrawable;->extractStateSet(Landroid/util/AttributeSet;)[I
 Landroid/graphics/drawable/StateListDrawable;->getStateCount()I
 Landroid/graphics/drawable/StateListDrawable;->getStateDrawable(I)Landroid/graphics/drawable/Drawable;
+Landroid/graphics/drawable/StateListDrawable;->getStateDrawableIndex([I)I
 Landroid/graphics/drawable/StateListDrawable;->getStateSet(I)[I
 Landroid/graphics/drawable/StateListDrawable;->mStateListState:Landroid/graphics/drawable/StateListDrawable$StateListState;
 Landroid/graphics/drawable/StateListDrawable;->updateStateFromTypedArray(Landroid/content/res/TypedArray;)V
@@ -622,6 +629,7 @@
 Landroid/graphics/SurfaceTexture;->mSurfaceTexture:J
 Landroid/graphics/SurfaceTexture;->nativeDetachFromGLContext()I
 Landroid/graphics/SurfaceTexture;->postEventFromNative(Ljava/lang/ref/WeakReference;)V
+Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;Ljava/lang/String;II)Landroid/graphics/Typeface;
 Landroid/graphics/Typeface;->mStyle:I
 Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface;
 Landroid/graphics/Typeface;->setDefault(Landroid/graphics/Typeface;)V
@@ -642,6 +650,7 @@
 Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager;
 Landroid/hardware/input/InputManager;->mIm:Landroid/hardware/input/IInputManager;
+Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
 Landroid/hardware/SerialPort;->mNativeContext:I
 Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->confidenceLevel:I
 Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;-><init>(II)V
@@ -676,17 +685,32 @@
 Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ)V
 Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
+Landroid/hardware/usb/UsbManager;->getPorts()[Landroid/hardware/usb/UsbPort;
+Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;)Landroid/hardware/usb/UsbPortStatus;
 Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
+Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V
+Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I
+Landroid/hardware/usb/UsbPortStatus;->isConnected()Z
+Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z
 Landroid/hardware/usb/UsbRequest;->mNativeContext:J
+Landroid/icu/impl/CurrencyData;-><init>()V
 Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
+Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
+Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
+Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
 Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateIntervalFormat;-><init>()V
 Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;-><init>()V
 Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -698,13 +722,23 @@
 Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
+Landroid/icu/text/SpoofChecker$ScriptSet;-><init>()V
+Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
+Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
 Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V
+Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
+Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
+Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
+Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
@@ -716,6 +750,10 @@
 Landroid/location/Country;->getSource()I
 Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
 Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
+Landroid/location/IFusedProvider$Stub;-><init>()V
+Landroid/location/IGeocodeProvider$Stub;-><init>()V
+Landroid/location/IGeofenceProvider$Stub;-><init>()V
+Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
 Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/location/LocationManager;->mService:Landroid/location/ILocationManager;
 Landroid/media/AudioAttributes;->mContentType:I
@@ -729,6 +767,8 @@
 Landroid/media/AudioFormat;->mChannelMask:I
 Landroid/media/AudioFormat;->mEncoding:I
 Landroid/media/AudioFormat;->mSampleRate:I
+Landroid/media/audiofx/AudioEffect;->command(I[B[B)I
+Landroid/media/audiofx/AudioEffect;->getParameter([I[B)I
 Landroid/media/audiofx/AudioEffect;-><init>(Ljava/util/UUID;Ljava/util/UUID;II)V
 Landroid/media/AudioGainConfig;-><init>(ILandroid/media/AudioGain;II[II)V
 Landroid/media/AudioGainConfig;->mChannelMask:I
@@ -739,6 +779,7 @@
 Landroid/media/AudioGain;-><init>(IIIIIIIII)V
 Landroid/media/AudioHandle;-><init>(I)V
 Landroid/media/AudioHandle;->mId:I
+Landroid/media/AudioManager;->forceVolumeControlStream(I)V
 Landroid/media/AudioManager;->getOutputLatency(I)I
 Landroid/media/AudioManager;->getService()Landroid/media/IAudioService;
 Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
@@ -775,9 +816,12 @@
 Landroid/media/AudioPort;->mGains:[Landroid/media/AudioGain;
 Landroid/media/AudioPort;->mHandle:Landroid/media/AudioHandle;
 Landroid/media/AudioPort;->mRole:I
+Landroid/media/AudioRecordingConfiguration;->getClientPackageName()Ljava/lang/String;
+Landroid/media/AudioRecordingConfiguration;->getClientUid()I
 Landroid/media/AudioRecord;->mNativeCallbackCookie:J
 Landroid/media/AudioRecord;->mNativeDeviceCallback:J
 Landroid/media/AudioRecord;->mNativeRecorderInJavaObj:J
+Landroid/media/AudioRecord;->native_release()V
 Landroid/media/AudioRecord;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
 Landroid/media/AudioSystem;->dynamicPolicyCallbackFromNative(ILjava/lang/String;I)V
 Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
@@ -785,15 +829,18 @@
 Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
 Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
 Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
+Landroid/media/AudioTrack;->deferred_connect(J)V
 Landroid/media/AudioTrack;->getLatency()I
 Landroid/media/AudioTrack;->mJniData:J
 Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J
 Landroid/media/AudioTrack;->mStreamType:I
+Landroid/media/AudioTrack;->native_release()V
 Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
 Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
 Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
 Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V
+Landroid/media/MediaCodec$CodecException;-><init>(IILjava/lang/String;)V
 Landroid/media/MediaCodec;->releaseOutputBuffer(IZZJ)V
 Landroid/media/MediaFile;->FIRST_AUDIO_FILE_TYPE:I
 Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFile$MediaFileType;
@@ -959,12 +1006,14 @@
 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;
 Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
 Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
 Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
+Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String;
 Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
 Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
 Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionListener;)V
@@ -1036,6 +1085,7 @@
 Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I
 Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
 Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
 Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
 Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
 Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
@@ -1082,7 +1132,9 @@
 Landroid/os/Message;->when:J
 Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
 Landroid/os/Parcel;->mNativePtr:J
+Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
 Landroid/os/Parcel$ReadWriteHelper;-><init>()V
+Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
 Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
 Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
 Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
@@ -1109,6 +1161,7 @@
 Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
 Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap;
 Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
+Landroid/os/SharedMemory;->getFd()I
 Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String;
 Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
 Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -1137,6 +1190,7 @@
 Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
 Landroid/os/StrictMode;->getThreadPolicyMask()I
 Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V
+Landroid/os/StrictMode$ThreadPolicy$Builder;->penaltyListener(Landroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)Landroid/os/StrictMode$ThreadPolicy$Builder;
 Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
 Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
 Landroid/os/SystemProperties;-><init>()V
@@ -1172,6 +1226,7 @@
 Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
 Landroid/os/UserManager;->getUserHandle()I
 Landroid/os/UserManager;->getUserHandle(I)I
+Landroid/os/UserManager;->getUserIcon(I)Landroid/graphics/Bitmap;
 Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
 Landroid/os/UserManager;->getUserSerialNumber(I)I
 Landroid/os/UserManager;->getUsers()Ljava/util/List;
@@ -1181,11 +1236,14 @@
 Landroid/os/VintfObject;->report()[Ljava/lang/String;
 Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
 Landroid/os/WorkSource;->add(I)Z
+Landroid/os/WorkSource;->addReturningNewbs(Landroid/os/WorkSource;)Landroid/os/WorkSource;
 Landroid/os/WorkSource;->get(I)I
 Landroid/os/WorkSource;->getName(I)Ljava/lang/String;
+Landroid/os/WorkSource;-><init>(I)V
 Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
 Landroid/os/WorkSource;->mNum:I
 Landroid/os/WorkSource;->mUids:[I
+Landroid/os/WorkSource;->setReturningDiffs(Landroid/os/WorkSource;)[Landroid/os/WorkSource;
 Landroid/os/WorkSource;->size()I
 Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder;
 Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable;
@@ -1451,11 +1509,43 @@
 Landroid/R$styleable;->Window_windowBackground:I
 Landroid/R$styleable;->Window_windowFrame:I
 Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
+Landroid/security/keystore/KeychainProtectionParams;->clearSecret()V
+Landroid/security/keystore/KeychainProtectionParams;->getKeyDerivationParams()Landroid/security/keystore/KeyDerivationParams;
+Landroid/security/keystore/KeychainProtectionParams;->getLockScreenUiFormat()I
+Landroid/security/keystore/KeychainProtectionParams;->getSecret()[B
+Landroid/security/keystore/KeychainProtectionParams;->getUserSecretType()I
+Landroid/security/keystore/KeychainProtectionParams;-><init>(IILandroid/security/keystore/KeyDerivationParams;[B)V
+Landroid/security/keystore/KeychainProtectionParams;-><init>(Landroid/os/Parcel;)V
+Landroid/security/keystore/KeychainProtectionParams;-><init>()V
+Landroid/security/keystore/KeychainSnapshot;->getCounterId()J
+Landroid/security/keystore/KeychainSnapshot;->getEncryptedRecoveryKeyBlob()[B
+Landroid/security/keystore/KeychainSnapshot;->getKeychainProtectionParams()Ljava/util/List;
+Landroid/security/keystore/KeychainSnapshot;->getMaxAttempts()I
+Landroid/security/keystore/KeychainSnapshot;->getServerParams()[B
+Landroid/security/keystore/KeychainSnapshot;->getSnapshotVersion()I
+Landroid/security/keystore/KeychainSnapshot;->getTrustedHardwarePublicKey()[B
+Landroid/security/keystore/KeychainSnapshot;->getWrappedApplicationKeys()Ljava/util/List;
+Landroid/security/keystore/KeyDerivationParams;->ALGORITHM_ARGON2ID:I
+Landroid/security/keystore/KeyDerivationParams;->ALGORITHM_SHA256:I
+Landroid/security/keystore/KeyDerivationParams;->createSha256Params([B)Landroid/security/keystore/KeyDerivationParams;
+Landroid/security/keystore/KeyDerivationParams;->getAlgorithm()I
+Landroid/security/keystore/KeyDerivationParams;->getSalt()[B
+Landroid/security/keystore/KeyDerivationParams;-><init>(I[B)V
+Landroid/security/keystore/KeyDerivationParams;-><init>(Landroid/os/Parcel;)V
+Landroid/security/keystore/RecoveryClaim;->getClaimBytes()[B
+Landroid/security/keystore/RecoveryClaim;->getRecoverySession()Landroid/security/keystore/RecoverySession;
 Landroid/security/keystore/RecoveryController;->getInstance()Landroid/security/keystore/RecoveryController;
+Landroid/security/keystore/RecoveryController;->getRecoveryData([B)Landroid/security/keystore/KeychainSnapshot;
 Landroid/security/keystore/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V
+Landroid/security/keystore/RecoveryController;->recoverKeys(Landroid/security/keystore/RecoverySession;[BLjava/util/List;)Ljava/util/Map;
 Landroid/security/keystore/RecoveryController;->setRecoverySecretTypes([I)V
+Landroid/security/keystore/RecoveryController;->setRecoveryStatus(Ljava/lang/String;[Ljava/lang/String;I)V
 Landroid/security/keystore/RecoveryController;->setServerParams([B)V
 Landroid/security/keystore/RecoveryController;->setSnapshotCreatedPendingIntent(Landroid/app/PendingIntent;)V
+Landroid/security/keystore/RecoveryController;->startRecoverySession([B[B[BLjava/util/List;)Landroid/security/keystore/RecoveryClaim;
+Landroid/security/keystore/WrappedApplicationKey;->getAlias()Ljava/lang/String;
+Landroid/security/keystore/WrappedApplicationKey;->getEncryptedKeyMaterial()[B
+Landroid/security/keystore/WrappedApplicationKey;-><init>(Ljava/lang/String;[B)V
 Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
 Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnectFailed()V
 Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnect(Ljava/lang/String;Landroid/media/session/MediaSession$Token;Landroid/os/Bundle;)V
@@ -1506,8 +1596,10 @@
 Landroid/telephony/SmsMessage;->getSubId()I
 Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telephony/SmsMessageBase;
 Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I
+Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List;
 Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
 Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
+Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
 Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
 Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I
 Landroid/telephony/SubscriptionManager;->getSubId(I)[I
@@ -1607,6 +1699,8 @@
 Landroid/text/TextPaint;->setUnderlineText(IF)V
 Landroid/transition/ChangeBounds;->BOTTOM_RIGHT_ONLY_PROPERTY:Landroid/util/Property;
 Landroid/transition/ChangeBounds;->POSITION_PROPERTY:Landroid/util/Property;
+Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal;
+Landroid/util/ArrayMap;->append(Ljava/lang/Object;Ljava/lang/Object;)V
 Landroid/util/ArrayMap;->mBaseCacheSize:I
 Landroid/util/ArrayMap;->mTwiceBaseCacheSize:I
 Landroid/util/DisplayMetrics;->noncompatHeightPixels:I
@@ -1622,6 +1716,8 @@
 Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime;
 Landroid/util/NtpTrustedTime;->hasCache()Z
 Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Rational;->mDenominator:I
+Landroid/util/Rational;->mNumerator:I
 Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
 Landroid/util/SparseIntArray;->mKeys:[I
@@ -1634,6 +1730,7 @@
 Landroid/view/accessibility/AccessibilityManager;->sInstance:Landroid/view/accessibility/AccessibilityManager;
 Landroid/view/accessibility/AccessibilityManager;->sInstanceSync:Ljava/lang/Object;
 Landroid/view/accessibility/AccessibilityNodeInfo;->refresh(Landroid/os/Bundle;Z)Z
+Landroid/view/accessibility/AccessibilityRecord;->getSourceNodeId()J
 Landroid/view/accessibility/IAccessibilityManager;->getEnabledAccessibilityServiceList(II)Ljava/util/List;
 Landroid/view/accessibility/IAccessibilityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/accessibility/IAccessibilityManager;
 Landroid/view/accessibility/IAccessibilityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -2116,6 +2213,73 @@
 Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
 Landroid/widget/VideoView;->mVideoHeight:I
 Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/ims/internal/uce/common/CapInfo;-><init>()V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCapTimestamp(J)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCdViaPresenceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setExts([Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtHttpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSnFSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtThumbSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFullSnFGroupChatSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPushSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setImSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVideoSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVoiceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIsSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoOnlyCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVoiceCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSmSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsDuringCSSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsSupported(Z)V
+Lcom/android/ims/internal/uce/common/StatusCode;-><init>()V
+Lcom/android/ims/internal/uce/common/StatusCode;->setStatusCode(I)V
+Lcom/android/ims/internal/uce/common/UceLong;->getUceLong()J
+Lcom/android/ims/internal/uce/common/UceLong;->setUceLong(J)V
+Lcom/android/ims/internal/uce/presence/PresCmdId;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresCmdId;->setCmdId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setStatus(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setUserData(I)V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->setPublishTrigeerType(I)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setDisplayName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setInstanceInfo(Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setResUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setPresentityUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResId(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResInstanceState(I)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setTupleInfo([Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setFullState(Z)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setListName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setPresSubscriptionState(Lcom/android/ims/internal/uce/presence/PresSubscriptionState;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionExpireTime(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionTerminatedReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setVersion(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setReasonPhrase(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRetryAfter(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setSipResponseCode(I)V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->setPresSubscriptionState(I)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setContactUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setFeatureTag(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setTimestamp(Ljava/lang/String;)V
 Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -2124,6 +2288,7 @@
 Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
 Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
+Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
 Lcom/android/internal/os/BatterySipper;->add(Lcom/android/internal/os/BatterySipper;)V
 Lcom/android/internal/os/BatterySipper;->drainType:Lcom/android/internal/os/BatterySipper$DrainType;
 Lcom/android/internal/os/BatterySipper;->getUid()I
@@ -2319,6 +2484,7 @@
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/util/FastPrintWriter;-><init>(Ljava/io/OutputStream;)V
 Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
 Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
 Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List;
@@ -2384,6 +2550,7 @@
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
 Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
 Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
+Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
 Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
 Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
 Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
@@ -2393,6 +2560,7 @@
 Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
 Ldalvik/system/CloseGuard;->warnIfOpen()V
 Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
+Ldalvik/system/DexFile;->isBackedByOatFile()Z
 Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
 Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2513,6 +2681,7 @@
 Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
 Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
 Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object;
 Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
 Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
@@ -2582,6 +2751,7 @@
 Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
 Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean;
 Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -2604,11 +2774,13 @@
 Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal;
 Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetDateTime;-><init>(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V
 Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
@@ -2715,6 +2887,7 @@
 Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Random;->seedUniquifier()J
 Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/regex/Matcher;->appendPos:I
 Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99c5d2b..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;
@@ -995,9 +996,9 @@
      * cursors for data being displayed, etc.
      *
      * <p>You can call {@link #finish} from within this function, in
-     * which case onDestroy() will be immediately called without any of the rest
-     * of the activity lifecycle ({@link #onStart}, {@link #onResume},
-     * {@link #onPause}, etc) executing.
+     * which case onDestroy() will be immediately called after {@link #onCreate} without any of the
+     * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
+     * executing.
      *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
@@ -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/Application.java b/core/java/android/app/Application.java
index 81cbbca..41eeb9a 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -191,6 +191,16 @@
         }
     }
 
+    /**
+     * Returns the name of the current process. A package's default process name
+     * is the same as its package name. Non-default processes will look like
+     * "$PACKAGE_NAME:$NAME", where $NAME corresponds to an android:process
+     * attribute within AndroidManifest.xml.
+     */
+    public static String getProcessName() {
+        return ActivityThread.currentProcessName();
+    }
+
     // ------------------ Internal API ------------------
 
     /**
@@ -333,4 +343,4 @@
         }
         return null;
     }
-}
\ No newline at end of file
+}
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/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b207d57..46d1264 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1072,20 +1072,77 @@
          * @hide
          */
         public static final int SUPPRESSED_EFFECTS_UNSET = -1;
+
         /**
          * Whether notifications suppressed by DND should not interrupt visually (e.g. with
          * notification lights or by turning the screen on) when the screen is off.
+         *
+         * @deprecated use {@link #SUPPRESSED_EFFECT_FULL_SCREEN_INTENT} and
+         * {@link #SUPPRESSED_EFFECT_AMBIENT} and {@link #SUPPRESSED_EFFECT_LIGHTS} individually.
          */
+        @Deprecated
         public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
         /**
          * Whether notifications suppressed by DND should not interrupt visually when the screen
          * is on (e.g. by peeking onto the screen).
+         *
+         * @deprecated use {@link #SUPPRESSED_EFFECT_PEEK}.
          */
+        @Deprecated
         public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
 
+        /**
+         * Whether {@link Notification#fullScreenIntent full screen intents} from
+         * notifications intercepted by DND are blocked.
+         */
+        public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 1 << 2;
+
+        /**
+         * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+         * notifications intercepted by DND are blocked.
+         */
+        public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 3;
+
+        /**
+         * Whether notifications intercepted by DND are prevented from peeking.
+         */
+        public static final int SUPPRESSED_EFFECT_PEEK = 1 << 4;
+
+        /**
+         * Whether notifications intercepted by DND are prevented from appearing in the status bar,
+         * on devices that support status bars.
+         */
+        public static final int SUPPRESSED_EFFECT_STATUS_BAR = 1 << 5;
+
+        /**
+         * Whether {@link NotificationChannel#canShowBadge() badges} from
+         * notifications intercepted by DND are blocked on devices that support badging.
+         */
+        public static final int SUPPRESSED_EFFECT_BADGE = 1 << 6;
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing on ambient displays
+         * on devices that support ambient display.
+         */
+        public static final int SUPPRESSED_EFFECT_AMBIENT = 1 << 7;
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing in notification
+         * list views like the notification shade or lockscreen on devices that support those
+         * views.
+         */
+        public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 1 << 8;
+
         private static final int[] ALL_SUPPRESSED_EFFECTS = {
                 SUPPRESSED_EFFECT_SCREEN_OFF,
                 SUPPRESSED_EFFECT_SCREEN_ON,
+                SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+                SUPPRESSED_EFFECT_LIGHTS,
+                SUPPRESSED_EFFECT_PEEK,
+                SUPPRESSED_EFFECT_STATUS_BAR,
+                SUPPRESSED_EFFECT_BADGE,
+                SUPPRESSED_EFFECT_AMBIENT,
+                SUPPRESSED_EFFECT_NOTIFICATION_LIST
         };
 
         /**
@@ -1097,6 +1154,12 @@
         /**
          * Constructs a policy for Do Not Disturb priority mode behavior.
          *
+         * <p>
+         *     Apps that target API levels below {@link Build.VERSION_CODES#P} cannot
+         *     change user-designated values to allow or disallow
+         *     {@link Policy#PRIORITY_CATEGORY_ALARMS}, {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and
+         *     {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd.
+         *
          * @param priorityCategories bitmask of categories of notifications that can bypass DND.
          * @param priorityCallSenders which callers can bypass DND.
          * @param priorityMessageSenders which message senders can bypass DND.
@@ -1109,6 +1172,26 @@
         /**
          * Constructs a policy for Do Not Disturb priority mode behavior.
          *
+         * <p>
+         *     Apps that target API levels below {@link Build.VERSION_CODES#P} cannot
+         *     change user-designated values to allow or disallow
+         *     {@link Policy#PRIORITY_CATEGORY_ALARMS}, {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and
+         *     {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd.
+         * <p>
+         *     Additionally, apps that target API levels below {@link Build.VERSION_CODES#P} can
+         *     only modify the {@link #SUPPRESSED_EFFECT_SCREEN_ON} and
+         *     {@link #SUPPRESSED_EFFECT_SCREEN_OFF} bits of the suppressed visual effects field.
+         *     All other suppressed effects will be ignored and reconstituted from the screen on
+         *     and screen off values.
+         * <p>
+         *     Apps that target {@link Build.VERSION_CODES#P} or above can set any
+         *     suppressed visual effects. However, if any suppressed effects >
+         *     {@link #SUPPRESSED_EFFECT_SCREEN_ON} are set, {@link #SUPPRESSED_EFFECT_SCREEN_ON}
+         *     and {@link #SUPPRESSED_EFFECT_SCREEN_OFF} will be ignored and reconstituted from
+         *     the more specific suppressed visual effect bits. Apps should migrate to targeting
+         *     specific effects instead of the deprecated {@link #SUPPRESSED_EFFECT_SCREEN_ON} and
+         *     {@link #SUPPRESSED_EFFECT_SCREEN_OFF} effects.
+         *
          * @param priorityCategories bitmask of categories of notifications that can bypass DND.
          * @param priorityCallSenders which callers can bypass DND.
          * @param priorityMessageSenders which message senders can bypass DND.
@@ -1190,6 +1273,30 @@
             }
         }
 
+        /**
+         * @hide
+         */
+        public static int getAllSuppressedVisualEffects() {
+            int effects = 0;
+            for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+                effects |= ALL_SUPPRESSED_EFFECTS[i];
+            }
+            return effects;
+        }
+
+        /**
+         * @hide
+         */
+        public static boolean areAllVisualEffectsSuppressed(int effects) {
+            for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+                final int effect = ALL_SUPPRESSED_EFFECTS[i];
+                if ((effects & effect) == 0) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static String suppressedEffectsToString(int effects) {
             if (effects <= 0) return "";
             final StringBuilder sb = new StringBuilder();
@@ -1228,9 +1335,26 @@
 
         private static String effectToString(int effect) {
             switch (effect) {
-                case SUPPRESSED_EFFECT_SCREEN_OFF: return "SUPPRESSED_EFFECT_SCREEN_OFF";
-                case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
-                case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
+                case SUPPRESSED_EFFECT_FULL_SCREEN_INTENT:
+                    return "SUPPRESSED_EFFECT_FULL_SCREEN_INTENT";
+                case SUPPRESSED_EFFECT_LIGHTS:
+                    return "SUPPRESSED_EFFECT_LIGHTS";
+                case SUPPRESSED_EFFECT_PEEK:
+                    return "SUPPRESSED_EFFECT_PEEK";
+                case SUPPRESSED_EFFECT_STATUS_BAR:
+                    return "SUPPRESSED_EFFECT_STATUS_BAR";
+                case SUPPRESSED_EFFECT_BADGE:
+                    return "SUPPRESSED_EFFECT_BADGE";
+                case SUPPRESSED_EFFECT_AMBIENT:
+                    return "SUPPRESSED_EFFECT_AMBIENT";
+                case SUPPRESSED_EFFECT_NOTIFICATION_LIST:
+                    return "SUPPRESSED_EFFECT_NOTIFICATION_LIST";
+                case SUPPRESSED_EFFECT_SCREEN_OFF:
+                    return "SUPPRESSED_EFFECT_SCREEN_OFF";
+                case SUPPRESSED_EFFECT_SCREEN_ON:
+                    return "SUPPRESSED_EFFECT_SCREEN_ON";
+                case SUPPRESSED_EFFECTS_UNSET:
+                    return "SUPPRESSED_EFFECTS_UNSET";
                 default: return "UNKNOWN_" + effect;
             }
         }
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index c2c91c2..b12e3bc 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -54,6 +54,12 @@
     public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID =
             "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
     /**
+     *   List<String> of the relevant statsd_config.proto's BroadcastSubscriberDetails.cookie.
+     *   Obtain using {@link android.content.Intent#getStringArrayListExtra(String)}.
+     */
+    public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES =
+            "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
+    /**
      * Extra of a {@link android.os.StatsDimensionsValue} representing sliced dimension value
      * information.
      */
@@ -146,7 +152,8 @@
      * {@link #EXTRA_STATS_CONFIG_UID},
      * {@link #EXTRA_STATS_CONFIG_KEY},
      * {@link #EXTRA_STATS_SUBSCRIPTION_ID},
-     * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
+     * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID},
+     * {@link #EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES}, and
      * {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
      * <p>
      * This function can only be called by the owner (uid) of the config. It must be called each
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/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 9f9ce8d..4f3cd63 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -60,6 +62,18 @@
             "android.intent.action.REQUEST_SLICE_PERMISSION";
 
     /**
+     * Category used to resolve intents that can be rendered as slices.
+     * <p>
+     * This category should be included on intent filters on providers that extend
+     * {@link SliceProvider}.
+     * @see SliceProvider
+     * @see SliceProvider#onMapIntentToUri(Intent)
+     * @see #mapIntentToUri(Intent)
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
+
+    /**
      * The meta-data key that allows an activity to easily be linked directly to a slice.
      * <p>
      * An activity can be statically linked to a slice uri by including a meta-data item
@@ -226,6 +240,18 @@
 
     /**
      * Turns a slice intent into a slice uri. Expects an explicit intent.
+     * <p>
+     * This goes through a several stage resolution process to determine if any slice
+     * can represent this intent.
+     *  - If the intent contains data that {@link ContentResolver#getType} is
+     *  {@link SliceProvider#SLICE_TYPE} then the data will be returned.
+     *  - If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
+     *  the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
+     *  will be returned.
+     *  - Lastly, if the intent explicitly points at an activity, and that activity has
+     *  meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
+     *  returned.
+     *  - If no slice is found, then {@code null} is returned.
      *
      * @param intent The intent associated with a slice.
      * @return The Slice Uri provided by the app or null if none exists.
@@ -245,8 +271,12 @@
             return intentData;
         }
         // Otherwise ask the app
+        Intent queryIntent = new Intent(intent);
+        if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
+            queryIntent.addCategory(CATEGORY_SLICE);
+        }
         List<ResolveInfo> providers =
-                mContext.getPackageManager().queryIntentContentProviders(intent, 0);
+                mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
         if (providers == null || providers.isEmpty()) {
             // There are no providers, see if this activity has a direct link.
             ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 64a5181..df32fb9 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -81,6 +81,7 @@
  *     android:authorities="com.example.mypkg">
  *     <intent-filter>
  *         <action android:name="com.example.mypkg.intent.action.MY_SLICE_INTENT" />
+ *         <category android:name="android.app.slice.category.SLICE" />
  *     </intent-filter>
  * </provider>}
  * </pre>
@@ -253,8 +254,13 @@
      * In that case, this method can be called and is expected to return a non-null Uri representing
      * a slice. Otherwise this will throw {@link UnsupportedOperationException}.
      *
+     * Any intent filter added to a slice provider should also contain
+     * {@link SliceManager#CATEGORY_SLICE}, because otherwise it will not be detected by
+     * {@link SliceManager#mapIntentToUri(Intent)}.
+     *
      * @return Uri representing the slice associated with the provided intent.
-     * @see {@link Slice}
+     * @see Slice
+     * @see SliceManager#mapIntentToUri(Intent)
      */
     public @NonNull Uri onMapIntentToUri(Intent intent) {
         throw new UnsupportedOperationException(
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/content/Intent.java b/core/java/android/content/Intent.java
index e7aead1..ce32278 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2448,6 +2448,23 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
+
+
+    /**
+     * Broadcast Action: Sent when the current battery level changes.
+     *
+     * It has {@link android.os.BatteryManager#EXTRA_EVENTS} that carries a list of {@link Bundle}
+     * instances representing individual battery level changes with associated
+     * extras from {@link #ACTION_BATTERY_CHANGED}.
+     *
+     * <p class="note">
+     * This broadcast requires {@link android.Manifest.permission#BATTERY_STATS} permission.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_BATTERY_LEVEL_CHANGED =
+            "android.intent.action.BATTERY_LEVEL_CHANGED";
     /**
      * Broadcast Action:  Indicates low battery condition on the device.
      * This broadcast corresponds to the "Low battery warning" system dialog.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 72db33f..f47d464 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -819,7 +819,8 @@
      * @param config A session configuration (see {@link SessionConfiguration}).
      *
      * @throws IllegalArgumentException In case the session configuration is invalid; or the output
-     *                                  configurations are empty.
+     *                                  configurations are empty; or the session configuration
+     *                                  executor is invalid.
      * @throws CameraAccessException In case the camera device is no longer connected or has
      *                               encountered a fatal error.
      * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
diff --git a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java b/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
deleted file mode 100644
index 866f370..0000000
--- a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * A dispatcher that replaces one argument with another; replaces any argument at an index
- * with another argument.
- *
- * <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always
- * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to
- * be something
- * that's not an {@code int}.</p>
- *
- * @param <T>
- *          source dispatch type, whose methods with {@link #dispatch} will be called
- * @param <TArg>
- *          argument replacement type, args in {@link #dispatch} matching {@code argumentIndex}
- *          will be overriden to objects of this type
- */
-public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> {
-
-    private final Dispatchable<T> mTarget;
-    private final int mArgumentIndex;
-    private final TArg mReplaceWith;
-
-    /**
-     * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target}
-     * after the argument is replaced.
-     *
-     * <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted
-     * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set
-     * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p>
-     *
-     * <p>If a method dispatched has less arguments than {@code argumentIndex}, it is
-     * passed through with the arguments unchanged.</p>
-     *
-     * @param target destination dispatch type, methods will be redirected to this dispatcher
-     * @param argumentIndex the numeric index of the argument {@code >= 0}
-     * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object
-     */
-    public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex,
-            TArg replaceWith) {
-        mTarget = checkNotNull(target, "target must not be null");
-        mArgumentIndex = checkArgumentNonnegative(argumentIndex,
-                "argumentIndex must not be negative");
-        mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null");
-    }
-
-    @Override
-    public Object dispatch(Method method, Object[] args) throws Throwable {
-
-        if (args.length > mArgumentIndex) {
-            args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches
-            args[mArgumentIndex] = mReplaceWith;
-        }
-
-        return mTarget.dispatch(method, args);
-    }
-
-    private static Object[] arrayCopy(Object[] array) {
-        int length = array.length;
-        Object[] newArray = new Object[length];
-        for (int i = 0; i < length; ++i) {
-            newArray[i] = array[i];
-        }
-        return newArray;
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java b/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
deleted file mode 100644
index fe575b2..0000000
--- a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Broadcast a single dispatch into multiple other dispatchables.
- *
- * <p>Every time {@link #dispatch} is invoked, all the broadcast targets will
- * see the same dispatch as well. The first target's return value is returned.</p>
- *
- * <p>This enables a single listener to be converted into a multi-listener.</p>
- */
-public class BroadcastDispatcher<T> implements Dispatchable<T> {
-
-    private final List<Dispatchable<T>> mDispatchTargets;
-
-    /**
-     * Create a broadcast dispatcher from the supplied dispatch targets.
-     *
-     * @param dispatchTargets one or more targets to dispatch to
-     */
-    @SafeVarargs
-    public BroadcastDispatcher(Dispatchable<T>... dispatchTargets) {
-        mDispatchTargets = Arrays.asList(
-                checkNotNull(dispatchTargets, "dispatchTargets must not be null"));
-    }
-
-    @Override
-    public Object dispatch(Method method, Object[] args) throws Throwable {
-        Object result = null;
-        boolean gotResult = false;
-
-        for (Dispatchable<T> dispatchTarget : mDispatchTargets) {
-            Object localResult = dispatchTarget.dispatch(method, args);
-
-            if (!gotResult) {
-                gotResult = true;
-                result = localResult;
-            }
-        }
-
-        return result;
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/Dispatchable.java b/core/java/android/hardware/camera2/dispatch/Dispatchable.java
deleted file mode 100644
index 753103f..0000000
--- a/core/java/android/hardware/camera2/dispatch/Dispatchable.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-/**
- * Dynamically dispatch a method and its argument to some object.
- *
- * <p>This can be used to intercept method calls and do work around them, redirect work,
- * or block calls entirely.</p>
- */
-public interface Dispatchable<T> {
-    /**
-     * Dispatch the method and arguments to this object.
-     * @param method a method defined in class {@code T}
-     * @param args arguments corresponding to said {@code method}
-     * @return the object returned when invoking {@code method}
-     * @throws Throwable any exception that might have been raised while invoking the method
-     */
-    public Object dispatch(Method method, Object[] args) throws Throwable;
-}
diff --git a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java b/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
deleted file mode 100644
index 75f97e4..0000000
--- a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Duck typing dispatcher; converts dispatch methods calls from one class to another by
- * looking up equivalently methods at runtime by name.
- *
- * <p>For example, if two types have identical method names and arguments, but
- * are not subclasses/subinterfaces of each other, this dispatcher will allow calls to be
- * made from one type to the other.</p>
- *
- * @param <TFrom> source dispatch type, whose methods with {@link #dispatch} will be called
- * @param <T> destination dispatch type, methods will be converted to the class of {@code T}
- */
-public class DuckTypingDispatcher<TFrom, T> implements Dispatchable<TFrom> {
-
-    private final MethodNameInvoker<T> mDuck;
-
-    /**
-     * Create a new duck typing dispatcher.
-     *
-     * @param target destination dispatch type, methods will be redirected to this dispatcher
-     * @param targetClass destination dispatch class, methods will be converted to this class's
-     */
-    public DuckTypingDispatcher(Dispatchable<T> target, Class<T> targetClass) {
-        checkNotNull(targetClass, "targetClass must not be null");
-        checkNotNull(target, "target must not be null");
-
-        mDuck = new MethodNameInvoker<T>(target, targetClass);
-    }
-
-    @Override
-    public Object dispatch(Method method, Object[] args) {
-        return mDuck.invoke(method.getName(), args);
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java b/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
deleted file mode 100644
index f8e9d49..0000000
--- a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.os.Handler;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Forward all interface calls into a handler by posting it as a {@code Runnable}.
- *
- * <p>All calls will return immediately; functions with return values will return a default
- * value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p>
- *
- * <p>Any exceptions thrown on the handler while trying to invoke a method
- * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any
- * checked exceptions to be thrown will result in "undefined" behavior
- * (although in practice it is usually thrown as normal).</p>
- */
-public class HandlerDispatcher<T> implements Dispatchable<T> {
-
-    private static final String TAG = "HandlerDispatcher";
-
-    private final Dispatchable<T> mDispatchTarget;
-    private final Handler mHandler;
-
-    /**
-     * Create a dispatcher that forwards it's dispatch calls by posting
-     * them onto the {@code handler} as a {@code Runnable}.
-     *
-     * @param dispatchTarget the destination whose method calls will be redirected into the handler
-     * @param handler all calls into {@code dispatchTarget} will be posted onto this handler
-     * @param <T> the type of the element you want to wrap.
-     * @return a dispatcher that will forward it's dispatch calls to a handler
-     */
-    public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) {
-        mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-        mHandler = checkNotNull(handler, "handler must not be null");
-    }
-
-    @Override
-    public Object dispatch(final Method method, final Object[] args) throws Throwable {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mDispatchTarget.dispatch(method, args);
-                } catch (InvocationTargetException e) {
-                    Throwable t = e.getTargetException();
-                    // Potential UB. Hopefully 't' is a runtime exception.
-                    UncheckedThrow.throwAnyException(t);
-                } catch (IllegalAccessException e) {
-                    // Impossible
-                    Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
-                } catch (IllegalArgumentException e) {
-                    // Impossible
-                    Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
-                } catch (Throwable e) {
-                    UncheckedThrow.throwAnyException(e);
-                }
-            }
-        });
-
-        // TODO handle primitive return values that would avoid NPE if unboxed
-        return null;
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java b/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
deleted file mode 100644
index ac5f526..0000000
--- a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-
-public class InvokeDispatcher<T> implements Dispatchable<T> {
-
-    private static final String TAG = "InvocationSink";
-    private final T mTarget;
-
-    public InvokeDispatcher(T target) {
-        mTarget = checkNotNull(target, "target must not be null");
-    }
-
-    @Override
-    public Object dispatch(Method method, Object[] args) {
-        try {
-            return method.invoke(mTarget, args);
-        } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            // Potential UB. Hopefully 't' is a runtime exception.
-            UncheckedThrow.throwAnyException(t);
-        } catch (IllegalAccessException e) {
-            // Impossible
-            Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
-        } catch (IllegalArgumentException e) {
-            // Impossible
-            Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
-        }
-
-        // unreachable
-        return null;
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
deleted file mode 100644
index 8296b7a..0000000
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
- *
- * @param <T> destination dispatch type, methods will be looked up in the class of {@code T}
- */
-public class MethodNameInvoker<T> {
-
-    private final Dispatchable<T> mTarget;
-    private final Class<T> mTargetClass;
-    private final Method[] mTargetClassMethods;
-    private final ConcurrentHashMap<String, Method> mMethods =
-            new ConcurrentHashMap<>();
-
-    /**
-     * Create a new method name invoker.
-     *
-     * @param target destination dispatch type, invokes will be redirected to this dispatcher
-     * @param targetClass destination dispatch class, the invoked methods will be from this class
-     */
-    public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
-        mTargetClass = targetClass;
-        mTargetClassMethods = targetClass.getMethods();
-        mTarget = target;
-    }
-
-    /**
-     * Invoke a method by its name.
-     *
-     * <p>If more than one method exists in {@code targetClass}, the first method with the right
-     * number of arguments will be used, and later calls will all use that method.</p>
-     *
-     * @param methodName
-     *          The name of the method, which will be matched 1:1 to the destination method
-     * @param params
-     *          Variadic parameter list.
-     * @return
-     *          The same kind of value that would normally be returned by calling {@code methodName}
-     *          statically.
-     *
-     * @throws IllegalArgumentException if {@code methodName} does not exist on the target class
-     * @throws Throwable will rethrow anything that the target method would normally throw
-     */
-    @SuppressWarnings("unchecked")
-    public <K> K invoke(String methodName, Object... params) {
-        checkNotNull(methodName, "methodName must not be null");
-
-        Method targetMethod = mMethods.get(methodName);
-        if (targetMethod == null) {
-            for (Method method : mTargetClassMethods) {
-                // TODO future: match types of params if possible
-                if (method.getName().equals(methodName) &&
-                        (params.length == method.getParameterTypes().length) ) {
-                    targetMethod = method;
-                    mMethods.put(methodName, targetMethod);
-                    break;
-                }
-            }
-
-            if (targetMethod == null) {
-                throw new IllegalArgumentException(
-                        "Method " + methodName + " does not exist on class " + mTargetClass);
-            }
-        }
-
-        try {
-            return (K) mTarget.dispatch(targetMethod, params);
-        } catch (Throwable e) {
-            UncheckedThrow.throwAnyException(e);
-            // unreachable
-            return null;
-        }
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java b/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
deleted file mode 100644
index fada075..0000000
--- a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-/**
- * Do nothing when dispatching; follows the null object pattern.
- */
-public class NullDispatcher<T> implements Dispatchable<T> {
-    /**
-     * Create a dispatcher that does nothing when dispatched to.
-     */
-    public NullDispatcher() {
-    }
-
-    /**
-     * Do nothing; all parameters are ignored.
-     */
-    @Override
-    public Object dispatch(Method method, Object[] args) {
-        return null;
-    }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/package.html b/core/java/android/hardware/camera2/dispatch/package.html
deleted file mode 100644
index 783d0a1..0000000
--- a/core/java/android/hardware/camera2/dispatch/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body>
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index c9eecf1..9e4cb80 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -15,16 +15,17 @@
  */
 package android.hardware.camera2.impl;
 
+import android.os.Binder;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.dispatch.Dispatchable;
-import android.hardware.camera2.dispatch.MethodNameInvoker;
 import android.view.Surface;
 
+import java.util.concurrent.Executor;
+
 import static com.android.internal.util.Preconditions.*;
 
 /**
@@ -34,164 +35,86 @@
  * to use our own proxy mechanism.</p>
  */
 public class CallbackProxies {
-
-    // TODO: replace with codegen
-
-    public static class DeviceStateCallbackProxy extends CameraDeviceImpl.StateCallbackKK {
-        private final MethodNameInvoker<CameraDeviceImpl.StateCallbackKK> mProxy;
-
-        public DeviceStateCallbackProxy(
-                Dispatchable<CameraDeviceImpl.StateCallbackKK> dispatchTarget) {
-            dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateCallbackKK.class);
-        }
-
-        @Override
-        public void onOpened(CameraDevice camera) {
-            mProxy.invoke("onOpened", camera);
-        }
-
-        @Override
-        public void onDisconnected(CameraDevice camera) {
-            mProxy.invoke("onDisconnected", camera);
-        }
-
-        @Override
-        public void onError(CameraDevice camera, int error) {
-            mProxy.invoke("onError", camera, error);
-        }
-
-        @Override
-        public void onUnconfigured(CameraDevice camera) {
-            mProxy.invoke("onUnconfigured", camera);
-        }
-
-        @Override
-        public void onActive(CameraDevice camera) {
-            mProxy.invoke("onActive", camera);
-        }
-
-        @Override
-        public void onBusy(CameraDevice camera) {
-            mProxy.invoke("onBusy", camera);
-        }
-
-        @Override
-        public void onClosed(CameraDevice camera) {
-            mProxy.invoke("onClosed", camera);
-        }
-
-        @Override
-        public void onIdle(CameraDevice camera) {
-            mProxy.invoke("onIdle", camera);
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback {
-        private final MethodNameInvoker<CameraDeviceImpl.CaptureCallback> mProxy;
-
-        public DeviceCaptureCallbackProxy(
-                Dispatchable<CameraDeviceImpl.CaptureCallback> dispatchTarget) {
-            dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureCallback.class);
-        }
-
-        @Override
-        public void onCaptureStarted(CameraDevice camera,
-                CaptureRequest request, long timestamp, long frameNumber) {
-            mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
-        }
-
-        @Override
-        public void onCapturePartial(CameraDevice camera,
-                CaptureRequest request, CaptureResult result) {
-            mProxy.invoke("onCapturePartial", camera, request, result);
-        }
-
-        @Override
-        public void onCaptureProgressed(CameraDevice camera,
-                CaptureRequest request, CaptureResult partialResult) {
-            mProxy.invoke("onCaptureProgressed", camera, request, partialResult);
-        }
-
-        @Override
-        public void onCaptureCompleted(CameraDevice camera,
-                CaptureRequest request, TotalCaptureResult result) {
-            mProxy.invoke("onCaptureCompleted", camera, request, result);
-        }
-
-        @Override
-        public void onCaptureFailed(CameraDevice camera,
-                CaptureRequest request, CaptureFailure failure) {
-            mProxy.invoke("onCaptureFailed", camera, request, failure);
-        }
-
-        @Override
-        public void onCaptureSequenceCompleted(CameraDevice camera,
-                int sequenceId, long frameNumber) {
-            mProxy.invoke("onCaptureSequenceCompleted", camera, sequenceId, frameNumber);
-        }
-
-        @Override
-        public void onCaptureSequenceAborted(CameraDevice camera,
-                int sequenceId) {
-            mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId);
-        }
-
-        @Override
-        public void onCaptureBufferLost(CameraDevice camera,
-                CaptureRequest request, Surface target, long frameNumber) {
-            mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber);
-        }
-
-    }
-
     public static class SessionStateCallbackProxy
             extends CameraCaptureSession.StateCallback {
-        private final MethodNameInvoker<CameraCaptureSession.StateCallback> mProxy;
+        private final Executor mExecutor;
+        private final CameraCaptureSession.StateCallback mCallback;
 
-        public SessionStateCallbackProxy(
-                Dispatchable<CameraCaptureSession.StateCallback> dispatchTarget) {
-            dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-            mProxy = new MethodNameInvoker<>(dispatchTarget,
-                    CameraCaptureSession.StateCallback.class);
+        public SessionStateCallbackProxy(Executor executor,
+                CameraCaptureSession.StateCallback callback) {
+            mExecutor = checkNotNull(executor, "executor must not be null");
+            mCallback = checkNotNull(callback, "callback must not be null");
         }
 
         @Override
         public void onConfigured(CameraCaptureSession session) {
-            mProxy.invoke("onConfigured", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onConfigured(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
 
         @Override
         public void onConfigureFailed(CameraCaptureSession session) {
-            mProxy.invoke("onConfigureFailed", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onConfigureFailed(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override
         public void onReady(CameraCaptureSession session) {
-            mProxy.invoke("onReady", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onReady(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override
         public void onActive(CameraCaptureSession session) {
-            mProxy.invoke("onActive", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onActive(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override
         public void onCaptureQueueEmpty(CameraCaptureSession session) {
-            mProxy.invoke("onCaptureQueueEmpty", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onCaptureQueueEmpty(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override
         public void onClosed(CameraCaptureSession session) {
-            mProxy.invoke("onClosed", session);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onClosed(session));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override
         public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
-            mProxy.invoke("onSurfacePrepared", session, surface);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onSurfacePrepared(session, surface));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
     }
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 8b8bbc3..f3f6c84 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -20,20 +20,18 @@
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher;
-import android.hardware.camera2.dispatch.BroadcastDispatcher;
-import android.hardware.camera2.dispatch.DuckTypingDispatcher;
-import android.hardware.camera2.dispatch.HandlerDispatcher;
-import android.hardware.camera2.dispatch.InvokeDispatcher;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.utils.TaskDrainer;
 import android.hardware.camera2.utils.TaskSingleDrainer;
+import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.util.Log;
 import android.view.Surface;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler;
 import static com.android.internal.util.Preconditions.*;
@@ -51,11 +49,11 @@
     private final Surface mInput;
     /**
      * User-specified state callback, used for outgoing events; calls to this object will be
-     * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
+     * automatically invoked via {@code mStateExecutor}.
      */
     private final CameraCaptureSession.StateCallback mStateCallback;
-    /** User-specified state handler used for outgoing state callback events */
-    private final Handler mStateHandler;
+    /** User-specified state executor used for outgoing state callback events */
+    private final Executor mStateExecutor;
 
     /** Internal camera device; used to translate calls into existing deprecated API */
     private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
@@ -87,7 +85,7 @@
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
     CameraCaptureSessionImpl(int id, Surface input,
-            CameraCaptureSession.StateCallback callback, Handler stateHandler,
+            CameraCaptureSession.StateCallback callback, Executor stateExecutor,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess) {
         if (callback == null) {
@@ -98,8 +96,8 @@
         mIdString = String.format("Session %d: ", mId);
 
         mInput = input;
-        mStateHandler = checkHandler(stateHandler);
-        mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
+        mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null");
+        mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback);
 
         mDeviceHandler = checkNotNull(deviceStateHandler, "deviceStateHandler must not be null");
         mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null");
@@ -110,12 +108,12 @@
          * This ensures total ordering between CameraDevice.StateCallback and
          * CameraDeviceImpl.CaptureCallback events.
          */
-        mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
-                /*name*/"seq");
-        mIdleDrainer = new TaskSingleDrainer(mDeviceHandler, new IdleDrainListener(),
-                /*name*/"idle");
-        mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
-                /*name*/"abort");
+        mSequenceDrainer = new TaskDrainer<>(new HandlerExecutor(mDeviceHandler),
+                new SequenceDrainListener(), /*name*/"seq");
+        mIdleDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+                new IdleDrainListener(), /*name*/"idle");
+        mAbortDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+                new AbortDrainListener(), /*name*/"abort");
 
         // CameraDevice should call configureOutputs and have it finish before constructing us
 
@@ -446,114 +444,140 @@
     }
 
     /**
-     * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code handler}.
+     * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}.
      */
-    private StateCallback createUserStateCallbackProxy(Handler handler, StateCallback callback) {
-        InvokeDispatcher<StateCallback> userCallbackSink = new InvokeDispatcher<>(callback);
-        HandlerDispatcher<StateCallback> handlerPassthrough =
-                new HandlerDispatcher<>(userCallbackSink, handler);
-
-        return new CallbackProxies.SessionStateCallbackProxy(handlerPassthrough);
+    private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) {
+        return new CallbackProxies.SessionStateCallbackProxy(executor, callback);
     }
 
     /**
      * Forward callbacks from
      * CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback.
      *
-     * <p>In particular, all calls are automatically split to go both to our own
-     * internal callback, and to the user-specified callback (by transparently posting
-     * to the user-specified handler).</p>
-     *
      * <p>When a capture sequence finishes, update the pending checked sequences set.</p>
      */
     @SuppressWarnings("deprecation")
     private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy(
             Handler handler, CaptureCallback callback) {
-        CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() {
+        final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler(
+                handler) : null;
 
+        return new CameraDeviceImpl.CaptureCallback() {
             @Override
             public void onCaptureStarted(CameraDevice camera,
                     CaptureRequest request, long timestamp, long frameNumber) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureStarted(
+                                    CameraCaptureSessionImpl.this, request, timestamp,
+                                    frameNumber));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
 
             @Override
             public void onCapturePartial(CameraDevice camera,
                     CaptureRequest request, android.hardware.camera2.CaptureResult result) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCapturePartial(
+                                    CameraCaptureSessionImpl.this, request, result));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
 
             @Override
             public void onCaptureProgressed(CameraDevice camera,
                     CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureProgressed(
+                                    CameraCaptureSessionImpl.this, request, partialResult));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
 
             @Override
             public void onCaptureCompleted(CameraDevice camera,
                     CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureCompleted(
+                                    CameraCaptureSessionImpl.this, request, result));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
 
             @Override
             public void onCaptureFailed(CameraDevice camera,
                     CaptureRequest request, android.hardware.camera2.CaptureFailure failure) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureFailed(
+                                    CameraCaptureSessionImpl.this, request, failure));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
 
             @Override
             public void onCaptureSequenceCompleted(CameraDevice camera,
                     int sequenceId, long frameNumber) {
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureSequenceCompleted(
+                                    CameraCaptureSessionImpl.this, sequenceId, frameNumber));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
                 finishPendingSequence(sequenceId);
             }
 
             @Override
             public void onCaptureSequenceAborted(CameraDevice camera,
                     int sequenceId) {
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureSequenceAborted(
+                                    CameraCaptureSessionImpl.this, sequenceId));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
                 finishPendingSequence(sequenceId);
             }
 
             @Override
             public void onCaptureBufferLost(CameraDevice camera,
                     CaptureRequest request, Surface target, long frameNumber) {
-                // Do nothing
+                if ((callback != null) && (executor != null)) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> callback.onCaptureBufferLost(
+                                    CameraCaptureSessionImpl.this, request, target, frameNumber));
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
             }
-
         };
-
-        /*
-         * Split the calls from the device callback into local callback and the following chain:
-         * - replace the first CameraDevice arg with a CameraCaptureSession
-         * - duck type from device callback to session callback
-         * - then forward the call to a handler
-         * - then finally invoke the destination method on the session callback object
-         */
-        if (callback == null) {
-            // OK: API allows the user to not specify a callback, and the handler may
-            // also be null in that case. Collapse whole dispatch chain to only call the local
-            // callback
-            return localCallback;
-        }
-
-        InvokeDispatcher<CameraDeviceImpl.CaptureCallback> localSink =
-                new InvokeDispatcher<>(localCallback);
-
-        InvokeDispatcher<CaptureCallback> userCallbackSink =
-                new InvokeDispatcher<>(callback);
-        HandlerDispatcher<CaptureCallback> handlerPassthrough =
-                new HandlerDispatcher<>(userCallbackSink, handler);
-        DuckTypingDispatcher<CameraDeviceImpl.CaptureCallback, CaptureCallback> duckToSession
-                = new DuckTypingDispatcher<>(handlerPassthrough, CaptureCallback.class);
-        ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureCallback, CameraCaptureSessionImpl>
-                replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
-                        /*argumentIndex*/0, this);
-
-        BroadcastDispatcher<CameraDeviceImpl.CaptureCallback> broadcaster =
-                new BroadcastDispatcher<CameraDeviceImpl.CaptureCallback>(
-                    replaceDeviceWithSession,
-                    localSink);
-
-        return new CallbackProxies.DeviceCaptureCallbackProxy(broadcaster);
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 06c2c25..4ee08ba 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -33,6 +33,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import static com.android.internal.util.Preconditions.*;
 
@@ -59,14 +60,14 @@
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
     CameraConstrainedHighSpeedCaptureSessionImpl(int id,
-            CameraCaptureSession.StateCallback callback, Handler stateHandler,
+            CameraCaptureSession.StateCallback callback, Executor stateExecutor,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess,
             CameraCharacteristics characteristics) {
         mCharacteristics = characteristics;
         CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
         mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
-                stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
+                stateExecutor, deviceImpl, deviceStateHandler, configureSuccess);
     }
 
     @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 511fa43..b328bb1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -35,8 +35,10 @@
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -58,6 +60,7 @@
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Executor;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -501,8 +504,9 @@
         for (Surface surface : outputs) {
             outConfigurations.add(new OutputConfiguration(surface));
         }
-        createCaptureSessionInternal(null, outConfigurations, callback, handler,
-                /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+        createCaptureSessionInternal(null, outConfigurations, callback,
+                checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+                /*sessionParams*/ null);
     }
 
     @Override
@@ -517,7 +521,7 @@
         // OutputConfiguration objects are immutable, but need to have our own array
         List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
 
-        createCaptureSessionInternal(null, currentOutputs, callback, handler,
+        createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
                 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
     }
 
@@ -537,8 +541,9 @@
         for (Surface surface : outputs) {
             outConfigurations.add(new OutputConfiguration(surface));
         }
-        createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler,
-                /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+        createCaptureSessionInternal(inputConfig, outConfigurations, callback,
+                checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+                /*sessionParams*/ null);
     }
 
     @Override
@@ -566,8 +571,8 @@
             currentOutputs.add(new OutputConfiguration(output));
         }
         createCaptureSessionInternal(inputConfig, currentOutputs,
-                callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
-                /*sessionParams*/ null);
+                callback, checkAndWrapHandler(handler),
+                /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
     }
 
     @Override
@@ -582,7 +587,8 @@
         for (Surface surface : outputs) {
             outConfigurations.add(new OutputConfiguration(surface));
         }
-        createCaptureSessionInternal(null, outConfigurations, callback, handler,
+        createCaptureSessionInternal(null, outConfigurations, callback,
+                checkAndWrapHandler(handler),
                 /*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
                 /*sessionParams*/ null);
     }
@@ -597,8 +603,8 @@
         for (OutputConfiguration output : outputs) {
             currentOutputs.add(new OutputConfiguration(output));
         }
-        createCaptureSessionInternal(inputConfig, currentOutputs, callback, handler, operatingMode,
-                /*sessionParams*/ null);
+        createCaptureSessionInternal(inputConfig, currentOutputs, callback,
+                checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
     }
 
     @Override
@@ -612,14 +618,17 @@
         if (outputConfigs == null) {
             throw new IllegalArgumentException("Invalid output configurations");
         }
+        if (config.getExecutor() == null) {
+            throw new IllegalArgumentException("Invalid executor");
+        }
         createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
-                config.getStateCallback(), config.getHandler(), config.getSessionType(),
+                config.getStateCallback(), config.getExecutor(), config.getSessionType(),
                 config.getSessionParameters());
     }
 
     private void createCaptureSessionInternal(InputConfiguration inputConfig,
             List<OutputConfiguration> outputConfigurations,
-            CameraCaptureSession.StateCallback callback, Handler handler,
+            CameraCaptureSession.StateCallback callback, Executor executor,
             int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
         synchronized(mInterfaceLock) {
             if (DEBUG) {
@@ -673,12 +682,11 @@
                 SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
 
                 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
-                        callback, handler, this, mDeviceHandler, configureSuccess,
+                        callback, executor, this, mDeviceHandler, configureSuccess,
                         mCharacteristics);
             } else {
                 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
-                        callback, handler, this, mDeviceHandler,
-                        configureSuccess);
+                        callback, executor, this, mDeviceHandler, configureSuccess);
             }
 
             // TODO: wait until current session closes, then create the new session
@@ -963,7 +971,12 @@
                         }
                     }
                 };
-                holder.getHandler().post(resultDispatch);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    holder.getExecutor().execute(resultDispatch);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             } else {
                 Log.w(TAG, String.format(
                         "did not register callback to request %d",
@@ -984,9 +997,9 @@
     private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
             Handler handler, boolean repeating) throws CameraAccessException {
 
-        // Need a valid handler, or current thread needs to have a looper, if
+        // Need a valid executor, or current thread needs to have a looper, if
         // callback is valid
-        handler = checkHandler(handler, callback);
+        Executor executor = getExecutor(handler, callback);
 
         // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
         // the surface isn't a physical stream surface for reprocessing request
@@ -1040,7 +1053,7 @@
             if (callback != null) {
                 mCaptureCallbackMap.put(requestInfo.getRequestId(),
                         new CaptureCallbackHolder(
-                            callback, requestList, handler, repeating, mNextSessionId - 1));
+                            callback, requestList, executor, repeating, mNextSessionId - 1));
             } else {
                 if (DEBUG) {
                     Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
@@ -1354,7 +1367,7 @@
         private final boolean mRepeating;
         private final CaptureCallback mCallback;
         private final List<CaptureRequest> mRequestList;
-        private final Handler mHandler;
+        private final Executor mExecutor;
         private final int mSessionId;
         /**
          * <p>Determine if the callback holder is for a constrained high speed request list that
@@ -1366,13 +1379,13 @@
         private final boolean mHasBatchedOutputs;
 
         CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
-                Handler handler, boolean repeating, int sessionId) {
-            if (callback == null || handler == null) {
+                Executor executor, boolean repeating, int sessionId) {
+            if (callback == null || executor == null) {
                 throw new UnsupportedOperationException(
                     "Must have a valid handler and a valid callback");
             }
             mRepeating = repeating;
-            mHandler = handler;
+            mExecutor = executor;
             mRequestList = new ArrayList<CaptureRequest>(requestList);
             mCallback = callback;
             mSessionId = sessionId;
@@ -1425,8 +1438,8 @@
             return getRequest(0);
         }
 
-        public Handler getHandler() {
-            return mHandler;
+        public Executor getExecutor() {
+            return mExecutor;
         }
 
         public int getSessionId() {
@@ -1810,7 +1823,12 @@
                         }
                     }
                 };
-                holder.getHandler().post(resultDispatch);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    holder.getExecutor().execute(resultDispatch);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
     }
@@ -1861,7 +1879,7 @@
         private void scheduleNotifyError(int code) {
             mInError = true;
             CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable(
-                    CameraDeviceCallbacks::notifyError, this, code));
+                        CameraDeviceCallbacks::notifyError, this, code));
         }
 
         private void notifyError(int code) {
@@ -1929,36 +1947,41 @@
                 if (isClosed()) return;
 
                 // Dispatch capture start notice
-                holder.getHandler().post(
-                    new Runnable() {
-                        @Override
-                        public void run() {
-                            if (!CameraDeviceImpl.this.isClosed()) {
-                                final int subsequenceId = resultExtras.getSubsequenceId();
-                                final CaptureRequest request = holder.getRequest(subsequenceId);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    holder.getExecutor().execute(
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                if (!CameraDeviceImpl.this.isClosed()) {
+                                    final int subsequenceId = resultExtras.getSubsequenceId();
+                                    final CaptureRequest request = holder.getRequest(subsequenceId);
 
-                                if (holder.hasBatchedOutputs()) {
-                                    // Send derived onCaptureStarted for requests within the batch
-                                    final Range<Integer> fpsRange =
-                                        request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
-                                    for (int i = 0; i < holder.getRequestCount(); i++) {
+                                    if (holder.hasBatchedOutputs()) {
+                                        // Send derived onCaptureStarted for requests within the
+                                        // batch
+                                        final Range<Integer> fpsRange =
+                                            request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+                                        for (int i = 0; i < holder.getRequestCount(); i++) {
+                                            holder.getCallback().onCaptureStarted(
+                                                CameraDeviceImpl.this,
+                                                holder.getRequest(i),
+                                                timestamp - (subsequenceId - i) *
+                                                NANO_PER_SECOND/fpsRange.getUpper(),
+                                                frameNumber - (subsequenceId - i));
+                                        }
+                                    } else {
                                         holder.getCallback().onCaptureStarted(
                                             CameraDeviceImpl.this,
-                                            holder.getRequest(i),
-                                            timestamp - (subsequenceId - i) *
-                                            NANO_PER_SECOND/fpsRange.getUpper(),
-                                            frameNumber - (subsequenceId - i));
+                                            holder.getRequest(resultExtras.getSubsequenceId()),
+                                            timestamp, frameNumber);
                                     }
-                                } else {
-                                    holder.getCallback().onCaptureStarted(
-                                        CameraDeviceImpl.this,
-                                        holder.getRequest(resultExtras.getSubsequenceId()),
-                                        timestamp, frameNumber);
                                 }
                             }
-                        }
-                    });
-
+                        });
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
 
@@ -2111,7 +2134,12 @@
                     finalResult = resultAsCapture;
                 }
 
-                holder.getHandler().post(resultDispatch);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    holder.getExecutor().execute(resultDispatch);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
 
                 // Collect the partials for a total result; or mark the frame as totally completed
                 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
@@ -2207,7 +2235,12 @@
                         }
                     };
                     // Dispatch the failure callback
-                    holder.getHandler().post(failureDispatch);
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        holder.getExecutor().execute(failureDispatch);
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
                 }
             } else {
                 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
@@ -2247,7 +2280,12 @@
                 checkAndFireSequenceComplete();
 
                 // Dispatch the failure callback
-                holder.getHandler().post(failureDispatch);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    holder.getExecutor().execute(failureDispatch);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
 
         }
@@ -2255,6 +2293,37 @@
     } // public class CameraDeviceCallbacks
 
     /**
+     * Instantiate a new Executor.
+     *
+     * <p>If the callback isn't null, check the handler and instantiate a new executor,
+     * otherwise instantiate a new executor in case handler is valid.</p>
+     */
+    static <T> Executor getExecutor(Handler handler, T callback) {
+        if (callback != null) {
+            return checkAndWrapHandler(handler);
+        }
+
+        if (handler != null) {
+            return new HandlerExecutor(handler);
+        }
+
+        return null;
+    }
+
+    /**
+     * Wrap Handler in Executor.
+     *
+     * <p>
+     * If handler is null, get the current thread's
+     * Looper to create a Executor with. If no looper exists, throw
+     * {@code IllegalArgumentException}.
+     * </p>
+     */
+    static Executor checkAndWrapHandler(Handler handler) {
+        return new HandlerExecutor(checkHandler(handler));
+    }
+
+    /**
      * Default handler management.
      *
      * <p>
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index a79a6c1..7bdb4a2 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -17,10 +17,10 @@
 
 package android.hardware.camera2.params;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.IntDef;
-import android.os.Handler;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.concurrent.Executor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -78,7 +79,7 @@
     private List<OutputConfiguration> mOutputConfigurations;
     private CameraCaptureSession.StateCallback mStateCallback;
     private int mSessionType;
-    private Handler mHandler = null;
+    private Executor mExecutor = null;
     private InputConfiguration mInputConfig = null;
     private CaptureRequest mSessionParameters = null;
 
@@ -87,10 +88,9 @@
      *
      * @param sessionType The session type.
      * @param outputs A list of output configurations for the capture session.
+     * @param executor The executor which should be used to invoke the callback. In general it is
+     *                 recommended that camera operations are not done on the main (UI) thread.
      * @param cb A state callback interface implementation.
-     * @param handler The handler on which the callback will be invoked. If it is
-     *                set to null, the callback will be invoked on the current thread's
-     *                {@link android.os.Looper looper}.
      *
      * @see #SESSION_REGULAR
      * @see #SESSION_HIGH_SPEED
@@ -101,11 +101,12 @@
      */
     public SessionConfiguration(@SessionMode int sessionType,
             @NonNull List<OutputConfiguration> outputs,
-            @NonNull CameraCaptureSession.StateCallback cb, @Nullable Handler handler) {
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull CameraCaptureSession.StateCallback cb) {
         mSessionType = sessionType;
         mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
         mStateCallback = cb;
-        mHandler = handler;
+        mExecutor = executor;
     }
 
     /**
@@ -136,14 +137,12 @@
     }
 
     /**
-     * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
+     * Retrieve the {@link java.util.concurrent.Executor} for the capture session.
      *
-     * @return The handler on which the callback will be invoked. If it is
-     *         set to null, the callback will be invoked on the current thread's
-     *         {@link android.os.Looper looper}.
+     * @return The Executor on which the callback will be invoked.
      */
-    public Handler getHandler() {
-        return mHandler;
+    public Executor getExecutor() {
+        return mExecutor;
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
index ed30ff3..e71f26a 100644
--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
@@ -15,11 +15,11 @@
  */
 package android.hardware.camera2.utils;
 
-import android.os.Handler;
 import android.util.Log;
 
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import static com.android.internal.util.Preconditions.*;
 
@@ -55,7 +55,7 @@
     private static final String TAG = "TaskDrainer";
     private final boolean DEBUG = false;
 
-    private final Handler mHandler;
+    private final Executor mExecutor;
     private final DrainListener mListener;
     private final String mName;
 
@@ -73,28 +73,27 @@
 
     /**
      * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
-     * via the {@code handler}.
+     * via the {@code executor}.
      *
-     * @param handler a non-{@code null} handler to use to post runnables to
+     * @param executor a non-{@code null} executor to use for listener execution
      * @param listener a non-{@code null} listener where {@code onDrained} will be called
      */
-    public TaskDrainer(Handler handler, DrainListener listener) {
-        mHandler = checkNotNull(handler, "handler must not be null");
+    public TaskDrainer(Executor executor, DrainListener listener) {
+        mExecutor = checkNotNull(executor, "executor must not be null");
         mListener = checkNotNull(listener, "listener must not be null");
         mName = null;
     }
 
     /**
      * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
-     * via the {@code handler}.
+     * via the {@code executor}.
      *
-     * @param handler a non-{@code null} handler to use to post runnables to
+     * @param executor a non-{@code null} executor to use for listener execution
      * @param listener a non-{@code null} listener where {@code onDrained} will be called
      * @param name an optional name used for debug logging
      */
-    public TaskDrainer(Handler handler, DrainListener listener, String name) {
-        // XX: Probably don't need a handler at all here
-        mHandler = checkNotNull(handler, "handler must not be null");
+    public TaskDrainer(Executor executor, DrainListener listener, String name) {
+        mExecutor = checkNotNull(executor, "executor must not be null");
         mListener = checkNotNull(listener, "listener must not be null");
         mName = name;
     }
@@ -200,15 +199,12 @@
     }
 
     private void postDrained() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
+        mExecutor.execute(() -> {
                 if (DEBUG) {
                     Log.v(TAG + "[" + mName + "]", "onDrained");
                 }
 
                 mListener.onDrained();
-            }
         });
     }
 }
diff --git a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
index f6272c9..9615450 100644
--- a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
@@ -16,7 +16,8 @@
 package android.hardware.camera2.utils;
 
 import android.hardware.camera2.utils.TaskDrainer.DrainListener;
-import android.os.Handler;
+
+import java.util.concurrent.Executor;
 
 /**
  * Keep track of a single concurrent task starting and finishing;
@@ -38,25 +39,25 @@
 
     /**
      * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
-     * via the {@code handler}.
+     * via the {@code executor}.
      *
-     * @param handler a non-{@code null} handler to use to post runnables to
+     * @param executor a non-{@code null} executor to use for listener execution
      * @param listener a non-{@code null} listener where {@code onDrained} will be called
      */
-    public TaskSingleDrainer(Handler handler, DrainListener listener) {
-        mTaskDrainer = new TaskDrainer<>(handler, listener);
+    public TaskSingleDrainer(Executor executor, DrainListener listener) {
+        mTaskDrainer = new TaskDrainer<>(executor, listener);
     }
 
     /**
      * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
-     * via the {@code handler}.
+     * via the {@code executor}.
      *
-     * @param handler a non-{@code null} handler to use to post runnables to
+     * @param executor a non-{@code null} executor to use for listener execution
      * @param listener a non-{@code null} listener where {@code onDrained} will be called
      * @param name an optional name used for debug logging
      */
-    public TaskSingleDrainer(Handler handler, DrainListener listener, String name) {
-        mTaskDrainer = new TaskDrainer<>(handler, listener, name);
+    public TaskSingleDrainer(Executor executor, DrainListener listener, String name) {
+        mTaskDrainer = new TaskDrainer<>(executor, listener, name);
     }
 
     /**
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 9e0c680..97868fa 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,8 +26,6 @@
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 /** @hide */
 interface IInputManager {
@@ -67,11 +65,6 @@
             String keyboardLayoutDescriptor);
     void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
-    KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
-            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
-    void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
-            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
-            String keyboardLayoutDescriptor);
 
     // Registers an input devices changed listener.
     void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index fdea5a2..6ae7a14 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.annotation.IntDef;
-import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
@@ -43,8 +42,6 @@
 import android.view.InputEvent;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.os.SomeArgs;
 
@@ -703,52 +700,6 @@
         }
     }
 
-
-    /**
-     * Gets the keyboard layout for the specified input device and IME subtype.
-     *
-     * @param identifier The identifier for the input device.
-     * @param inputMethodInfo The input method.
-     * @param inputMethodSubtype The input method subtype. {@code null} if this input method does
-     * not support any subtype.
-     *
-     * @return The associated {@link KeyboardLayout}, or null if one has not been set.
-     *
-     * @hide
-     */
-    @Nullable
-    public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
-        try {
-            return mIm.getKeyboardLayoutForInputDevice(
-                    identifier, inputMethodInfo, inputMethodSubtype);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Sets the keyboard layout for the specified input device and IME subtype pair.
-     *
-     * @param identifier The identifier for the input device.
-     * @param inputMethodInfo The input method with which to associate the keyboard layout.
-     * @param inputMethodSubtype The input method subtype which which to associate the keyboard
-     * layout. {@code null} if this input method does not support any subtype.
-     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
-     *
-     * @hide
-     */
-    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
-            String keyboardLayoutDescriptor) {
-        try {
-            mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
-                    inputMethodSubtype, keyboardLayoutDescriptor);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
     /**
      * Gets the TouchCalibration applied to the specified input device's coordinates.
      *
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 4ea0f55..eb7ea67 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -16,11 +16,8 @@
 
 package android.hardware.input;
 
-import android.annotation.Nullable;
 import android.hardware.display.DisplayViewport;
 import android.view.InputEvent;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import java.util.List;
 
@@ -46,16 +43,6 @@
     public abstract void setInteractive(boolean interactive);
 
     /**
-     * Notifies that InputMethodManagerService switched the current input method subtype.
-     *
-     * @param userId user id that indicates who is using the specified input method and subtype.
-     * @param inputMethodInfo {@code null} when no input method is selected.
-     * @param subtype {@code null} when {@code inputMethodInfo} does has no subtype.
-     */
-    public abstract void onInputMethodSubtypeChanged(int userId,
-            @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype);
-
-    /**
      * Toggles Caps Lock state for input device with specific id.
      *
      * @param deviceId The id of input device.
diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java
index 15503ed..025fad0 100644
--- a/core/java/android/hardware/input/TouchCalibration.java
+++ b/core/java/android/hardware/input/TouchCalibration.java
@@ -123,10 +123,4 @@
                Float.floatToIntBits(mYScale)  ^
                Float.floatToIntBits(mYOffset);
     }
-
-    @Override
-    public String toString() {
-        return String.format("[%f, %f, %f, %f, %f, %f]",
-                mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset);
-    }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 71266a0..36f359b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -453,133 +453,177 @@
     public static final int TYPE_NONE        = -1;
 
     /**
-     * The Mobile data connection.  When active, all data traffic
-     * will use this network type's interface by default
-     * (it has a default route)
+     * A Mobile data connection. Devices may support more than one.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
+    @Deprecated
     public static final int TYPE_MOBILE      = 0;
+
     /**
-     * The WIFI data connection.  When active, all data traffic
-     * will use this network type's interface by default
-     * (it has a default route).
+     * A WIFI data connection. Devices may support more than one.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
+    @Deprecated
     public static final int TYPE_WIFI        = 1;
+
     /**
      * An MMS-specific Mobile data connection.  This network type may use the
      * same network interface as {@link #TYPE_MOBILE} or it may use a different
      * one.  This is used by applications needing to talk to the carrier's
      * Multimedia Messaging Service servers.
      *
-     * @deprecated Applications should instead use
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
      *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
      *         provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability.
      */
     @Deprecated
     public static final int TYPE_MOBILE_MMS  = 2;
+
     /**
      * A SUPL-specific Mobile data connection.  This network type may use the
      * same network interface as {@link #TYPE_MOBILE} or it may use a different
      * one.  This is used by applications needing to talk to the carrier's
      * Secure User Plane Location servers for help locating the device.
      *
-     * @deprecated Applications should instead use
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
      *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
      *         provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability.
      */
     @Deprecated
     public static final int TYPE_MOBILE_SUPL = 3;
+
     /**
      * A DUN-specific Mobile data connection.  This network type may use the
      * same network interface as {@link #TYPE_MOBILE} or it may use a different
      * one.  This is sometimes by the system when setting up an upstream connection
      * for tethering so that the carrier is aware of DUN traffic.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
+     *         provides the {@link NetworkCapabilities#NET_CAPABILITY_DUN} capability.
      */
+    @Deprecated
     public static final int TYPE_MOBILE_DUN  = 4;
+
     /**
      * A High Priority Mobile data connection.  This network type uses the
      * same network interface as {@link #TYPE_MOBILE} but the routing setup
      * is different.
      *
-     * @deprecated Applications should instead use
-     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
-     *         uses the {@link NetworkCapabilities#TRANSPORT_CELLULAR} transport.
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
     @Deprecated
     public static final int TYPE_MOBILE_HIPRI = 5;
+
     /**
-     * The WiMAX data connection.  When active, all data traffic
-     * will use this network type's interface by default
-     * (it has a default route).
+     * A WiMAX data connection.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
+    @Deprecated
     public static final int TYPE_WIMAX       = 6;
 
     /**
-     * The Bluetooth data connection.  When active, all data traffic
-     * will use this network type's interface by default
-     * (it has a default route).
+     * A Bluetooth data connection.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
+    @Deprecated
     public static final int TYPE_BLUETOOTH   = 7;
 
     /**
      * Dummy data connection.  This should not be used on shipping devices.
+     * @deprecated This is not used any more.
      */
+    @Deprecated
     public static final int TYPE_DUMMY       = 8;
 
     /**
-     * The Ethernet data connection.  When active, all data traffic
-     * will use this network type's interface by default
-     * (it has a default route).
+     * An Ethernet data connection.
+     *
+     * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+     *         {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+     *         appropriate network. {@see NetworkCapabilities} for supported transports.
      */
+    @Deprecated
     public static final int TYPE_ETHERNET    = 9;
 
     /**
      * Over the air Administration.
+     * @deprecated Use {@link NetworkCapabilities} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_MOBILE_FOTA = 10;
 
     /**
      * IP Multimedia Subsystem.
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IMS} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_MOBILE_IMS  = 11;
 
     /**
      * Carrier Branded Services.
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_CBS} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_MOBILE_CBS  = 12;
 
     /**
      * A Wi-Fi p2p connection. Only requesting processes will have access to
      * the peers connected.
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_WIFI_P2P} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_WIFI_P2P    = 13;
 
     /**
      * The network to use for initially attaching to the network
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IA} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_MOBILE_IA = 14;
 
     /**
      * Emergency PDN connection for emergency services.  This
      * may include IMS and MMS in emergency situations.
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_EIMS} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_MOBILE_EMERGENCY = 15;
 
     /**
      * The network that uses proxy to achieve connectivity.
+     * @deprecated Use {@link NetworkCapabilities} instead.
      * {@hide}
      */
+    @Deprecated
     public static final int TYPE_PROXY = 16;
 
     /**
      * A virtual network using one or more native bearers.
      * It may or may not be providing security services.
+     * @deprecated Applications should use {@link NetworkCapabilities#TRANSPORT_VPN} instead.
      */
+    @Deprecated
     public static final int TYPE_VPN = 17;
 
     /** {@hide} */
@@ -686,8 +730,10 @@
      * @param type the type needing naming
      * @return a String for the given type, or a string version of the type ("87")
      * if no name is known.
+     * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
      * {@hide}
      */
+    @Deprecated
     public static String getNetworkTypeName(int type) {
         switch (type) {
           case TYPE_NONE:
@@ -738,8 +784,10 @@
      * This should be replaced in the future by a network property.
      * @param networkType the type to check
      * @return a boolean - {@code true} if uses cellular network, else {@code false}
+     * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
      * {@hide}
      */
+    @Deprecated
     public static boolean isNetworkTypeMobile(int networkType) {
         switch (networkType) {
             case TYPE_MOBILE:
@@ -761,8 +809,10 @@
     /**
      * Checks if the given network type is backed by a Wi-Fi radio.
      *
+     * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
      * @hide
      */
+    @Deprecated
     public static boolean isNetworkTypeWifi(int networkType) {
         switch (networkType) {
             case TYPE_WIFI:
@@ -1529,6 +1579,8 @@
      * IllegalArgumentException if no mapping from the legacy type to
      * NetworkCapabilities is known.
      *
+     * @deprecated Types are deprecated. Use {@link NetworkCallback} or {@link NetworkRequest}
+     *     to find the network instead.
      * @hide
      */
     public static NetworkCapabilities networkCapabilitiesForType(int type) {
@@ -2380,6 +2432,7 @@
      *
      * @param networkType The type of network you want to report on
      * @param percentage The quality of the connection 0 is bad, 100 is good
+     * @deprecated Types are deprecated. Use {@link #reportNetworkConnectivity} instead.
      * {@hide}
      */
     public void reportInetCondition(int networkType, int percentage) {
@@ -2511,9 +2564,10 @@
      *
      * @param networkType The network type we'd like to check
      * @return {@code true} if supported, else {@code false}
-     *
+     * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
      * @hide
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public boolean isNetworkSupported(int networkType) {
         try {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index e6ad89a..999771a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -38,14 +38,18 @@
      * <table>
      * <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
      * <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
-     * <tr><td><code>SCANNING</code></td><td><code>CONNECTING</code></td></tr>
+     * <tr><td><code>SCANNING</code></td><td><code>DISCONNECTED</code></td></tr>
      * <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
      * <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
+     * <tr><td><code>OBTAINING_IPADDR</code></td><td><code>CONNECTING</code></td></tr>
+     * <tr><td><code>VERIFYING_POOR_LINK</code></td><td><code>CONNECTING</code></td></tr>
+     * <tr><td><code>CAPTIVE_PORTAL_CHECK</code></td><td><code>CONNECTING</code></td></tr>
      * <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
+     * <tr><td><code>SUSPENDED</code></td><td><code>SUSPENDED</code></td></tr>
      * <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
      * <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
-     * <tr><td><code>UNAVAILABLE</code></td><td><code>DISCONNECTED</code></td></tr>
      * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
+     * <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
      * </table>
      */
     public enum State {
@@ -163,8 +167,17 @@
      * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
      * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
      * ConnectivityManager#TYPE_ETHERNET},  {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
-     * types defined by {@link ConnectivityManager}
+     * types defined by {@link ConnectivityManager}.
+     * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
+     *             instead with one of the NetworkCapabilities#TRANSPORT_* constants :
+     *             {@link #getType} and {@link #getTypeName} cannot account for networks using
+     *             multiple transports. Note that generally apps should not care about transport;
+     *             {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
+     *             {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
+     *             apps concerned with meteredness or bandwidth should be looking at, as they
+     *             offer this information with much better accuracy.
      */
+    @Deprecated
     public int getType() {
         synchronized (this) {
             return mNetworkType;
@@ -172,8 +185,10 @@
     }
 
     /**
+     * @deprecated Use {@link NetworkCapabilities} instead
      * @hide
      */
+    @Deprecated
     public void setType(int type) {
         synchronized (this) {
             mNetworkType = type;
@@ -205,7 +220,16 @@
      * Return a human-readable name describe the type of the network,
      * for example "WIFI" or "MOBILE".
      * @return the name of the network type
+     * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
+     *             instead with one of the NetworkCapabilities#TRANSPORT_* constants :
+     *             {@link #getType} and {@link #getTypeName} cannot account for networks using
+     *             multiple transports. Note that generally apps should not care about transport;
+     *             {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
+     *             {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
+     *             apps concerned with meteredness or bandwidth should be looking at, as they
+     *             offer this information with much better accuracy.
      */
+    @Deprecated
     public String getTypeName() {
         synchronized (this) {
             return mTypeName;
@@ -230,7 +254,15 @@
      * that the network is fully usable.
      * @return {@code true} if network connectivity exists or is in the process
      * of being established, {@code false} otherwise.
+     * @deprecated Apps should instead use the
+     *             {@link android.net.ConnectivityManager.NetworkCallback} API to
+     *             learn about connectivity changes.
+     *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
+     *             {@link ConnectivityManager#registerNetworkCallback}. These will
+     *             give a more accurate picture of the connectivity state of
+     *             the device and let apps react more easily and quickly to changes.
      */
+    @Deprecated
     public boolean isConnectedOrConnecting() {
         synchronized (this) {
             return mState == State.CONNECTED || mState == State.CONNECTING;
@@ -259,8 +291,18 @@
      * data roaming has been disabled.</li>
      * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
      * </ul>
+     * Since Android L, this always returns {@code true}, because the system only
+     * returns info for available networks.
      * @return {@code true} if the network is available, {@code false} otherwise
+     * @deprecated Apps should instead use the
+     *             {@link android.net.ConnectivityManager.NetworkCallback} API to
+     *             learn about connectivity changes.
+     *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
+     *             {@link ConnectivityManager#registerNetworkCallback}. These will
+     *             give a more accurate picture of the connectivity state of
+     *             the device and let apps react more easily and quickly to changes.
      */
+    @Deprecated
     public boolean isAvailable() {
         synchronized (this) {
             return mIsAvailable;
@@ -270,9 +312,11 @@
     /**
      * Sets if the network is available, ie, if the connectivity is possible.
      * @param isAvailable the new availability value.
+     * @deprecated Use {@link NetworkCapabilities} instead
      *
      * @hide
      */
+    @Deprecated
     public void setIsAvailable(boolean isAvailable) {
         synchronized (this) {
             mIsAvailable = isAvailable;
@@ -285,7 +329,10 @@
      * network following a disconnect from another network.
      * @return {@code true} if this is a failover attempt, {@code false}
      * otherwise.
+     * @deprecated This field is not populated in recent Android releases,
+     *             and does not make a lot of sense in a multi-network world.
      */
+    @Deprecated
     public boolean isFailover() {
         synchronized (this) {
             return mIsFailover;
@@ -296,8 +343,10 @@
      * Set the failover boolean.
      * @param isFailover {@code true} to mark the current connection attempt
      * as a failover.
+     * @deprecated This hasn't been set in any recent Android release.
      * @hide
      */
+    @Deprecated
     public void setFailover(boolean isFailover) {
         synchronized (this) {
             mIsFailover = isFailover;
@@ -322,7 +371,10 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead.
+     * {@hide}
+     */
     @VisibleForTesting
     @Deprecated
     public void setRoaming(boolean isRoaming) {
@@ -334,7 +386,15 @@
     /**
      * Reports the current coarse-grained state of the network.
      * @return the coarse-grained state
+     * @deprecated Apps should instead use the
+     *             {@link android.net.ConnectivityManager.NetworkCallback} API to
+     *             learn about connectivity changes.
+     *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
+     *             {@link ConnectivityManager#registerNetworkCallback}. These will
+     *             give a more accurate picture of the connectivity state of
+     *             the device and let apps react more easily and quickly to changes.
      */
+    @Deprecated
     public State getState() {
         synchronized (this) {
             return mState;
@@ -358,8 +418,10 @@
      * if one was supplied. May be {@code null}.
      * @param extraInfo an optional {@code String} providing addditional network state
      * information passed up from the lower networking layers.
+     * @deprecated Use {@link NetworkCapabilities} instead.
      * @hide
      */
+    @Deprecated
     public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
         synchronized (this) {
             this.mDetailedState = detailedState;
@@ -385,6 +447,8 @@
      * Report the reason an attempt to establish connectivity failed,
      * if one is available.
      * @return the reason for failure, or null if not available
+     * @deprecated This method does not have a consistent contract that could make it useful
+     *             to callers.
      */
     public String getReason() {
         synchronized (this) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 8b4f02e..6363161 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.Intent;
@@ -138,6 +139,23 @@
      */
     public static final String EXTRA_SEQUENCE = "seq";
 
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
+     * Contains list of Bundles representing battery events
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_EVENTS = "android.os.extra.EVENTS";
+
+    /**
+     * Extra for event in {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
+     * Long value representing time when event occurred as returned by
+     * {@link android.os.SystemClock#elapsedRealtime()}
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
+
     // values for "status" field in the ACTION_BATTERY_CHANGED Intent
     public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
     public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 29c298e..402c995 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -74,6 +74,7 @@
      */
     oneway void sendSubscriberBroadcast(in IBinder intentSender, long configUid, long configId,
                                         long subscriptionId, long subscriptionRuleId,
+                                        in String[] cookies,
                                         in StatsDimensionsValue dimensionsValue);
 
     /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index c7d89b0..2cb5aee 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -141,6 +141,14 @@
     public abstract void setDozeOverrideFromDreamManager(
             int screenState, int screenBrightness);
 
+    /**
+     * Used by sidekick manager to tell the power manager if it shouldn't change the display state
+     * when a draw wake lock is acquired. Some processes may grab such a wake lock to do some work
+     * in a powered-up state, but we shouldn't give up sidekick control over the display until this
+     * override is lifted.
+     */
+    public abstract void setDrawWakeLockOverrideFromSidekick(boolean keepState);
+
     public abstract PowerSaveState getLowPowerState(int serviceType);
 
     public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index fb11d00..8aef012 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -228,6 +228,25 @@
     /** @hide */
     public static final String RES_CAN_BLOCK_NUMBERS = "can_block";
 
+    /** @hide */
+    public static final String RES_ENHANCED_SETTING_IS_ENABLED = "enhanced_setting_enabled";
+
+    /** @hide */
+    public static final String RES_SHOW_EMERGENCY_CALL_NOTIFICATION =
+            "show_emergency_call_notification";
+
+    /** @hide */
+    public static final String EXTRA_ENHANCED_SETTING_KEY = "extra_enhanced_setting_key";
+
+    /** @hide */
+    public static final String EXTRA_ENHANCED_SETTING_VALUE = "extra_enhanced_setting_value";
+
+    /** @hide */
+    public static final String EXTRA_CONTACT_EXIST = "extra_contact_exist";
+
+    /** @hide */
+    public static final String EXTRA_CALL_PRESENTATION = "extra_call_presentation";
+
     /**
      * Returns whether a given number is in the blocked list.
      *
@@ -314,11 +333,33 @@
         public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
                 "get_block_suppression_status";
 
+        public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
+                "should_show_emergency_call_notification";
+
         public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
 
         public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
                 "blocking_suppressed_until_timestamp";
 
+        public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
+        public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
+
+        /* Preference key of block numbers not in contacts setting. */
+        public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED =
+                "block_numbers_not_in_contacts_setting";
+        /* Preference key of block private number calls setting. */
+        public static final String ENHANCED_SETTING_KEY_BLOCK_PRIVATE =
+                "block_private_number_calls_setting";
+        /* Preference key of block payphone calls setting. */
+        public static final String ENHANCED_SETTING_KEY_BLOCK_PAYPHONE =
+                "block_payphone_calls_setting";
+        /* Preference key of block unknown calls setting. */
+        public static final String ENHANCED_SETTING_KEY_BLOCK_UNKNOWN =
+                "block_unknown_calls_setting";
+        /* Preference key for whether should show an emergency call notification. */
+        public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION =
+                "show_emergency_call_notification";
+
         /**
          * Notifies the provider that emergency services were contacted by the user.
          * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
@@ -342,13 +383,19 @@
 
         /**
          * Returns {@code true} if {@code phoneNumber} is blocked taking
-         * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
-         * not been contacted recently, this method is equivalent to
-         * {@link #isBlocked(Context, String)}.
+         * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services
+         * have not been contacted recently and enhanced call blocking not been enabled, this
+         * method is equivalent to {@link #isBlocked(Context, String)}.
+         *
+         * @param context the context of the caller.
+         * @param phoneNumber the number to check.
+         * @param extras the extra attribute of the number.
+         * @return {@code true} if should block the number. {@code false} otherwise.
          */
-        public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+        public static boolean shouldSystemBlockNumber(Context context, String phoneNumber,
+                Bundle extras) {
             final Bundle res = context.getContentResolver().call(
-                    AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+                    AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras);
             return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
         }
 
@@ -363,9 +410,62 @@
         }
 
         /**
-         * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
-         * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
-         * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+         * Check whether should show the emergency call notification.
+         *
+         * @param context the context of the caller.
+         * @return {@code true} if should show emergency call notification. {@code false} otherwise.
+         */
+        public static boolean shouldShowEmergencyCallNotification(Context context) {
+            final Bundle res = context.getContentResolver().call(
+                    AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null);
+            return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false);
+        }
+
+        /**
+         * Check whether the enhanced block setting is enabled.
+         *
+         * @param context the context of the caller.
+         * @param key the key of the setting to check, can be
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+         *        {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+         * @return {@code true} if the setting is enabled. {@code false} otherwise.
+         */
+        public static boolean getEnhancedBlockSetting(Context context, String key) {
+            Bundle extras = new Bundle();
+            extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+            final Bundle res = context.getContentResolver().call(
+                    AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras);
+            return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false);
+        }
+
+        /**
+         * Set the enhanced block setting enabled status.
+         *
+         * @param context the context of the caller.
+         * @param key the key of the setting to set, can be
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+         *        {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+         *        {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+         * @param value the enabled statue of the setting to set.
+         */
+        public static void setEnhancedBlockSetting(Context context, String key, boolean value) {
+            Bundle extras = new Bundle();
+            extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+            extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value);
+            context.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING,
+                    null, extras);
+        }
+
+        /**
+         * Represents the current status of
+         * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services
+         * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking
+         * is disabled until the timestamp {@link #untilTimestampMillis}.
          */
         public static class BlockSuppressionStatus {
             public final boolean isSuppressed;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index d9808a3..1da6602 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -692,8 +692,8 @@
             // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
             // If the magic is non-zero, we simply return thumbnail if it does exist.
             // querying MediaProvider and simply return thumbnail.
-            MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
-                    : Images.Media.EXTERNAL_CONTENT_URI);
+            MiniThumbFile thumbFile = MiniThumbFile.instance(
+                    isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
             Cursor c = null;
             try {
                 long magic = thumbFile.getMagic(origId);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e952cab..29b7931 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6184,10 +6184,13 @@
 
         /**
          * Integer property that specifies the type of color space adjustment to
-         * perform. Valid values are defined in AccessibilityManager:
+         * perform. Valid values are defined in AccessibilityManager and Settings arrays.xml:
          * - AccessibilityManager.DALTONIZER_DISABLED = -1
          * - AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY = 0
-         * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY = 12
+         * - <item>@string/daltonizer_mode_protanomaly</item> = 11
+         * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY and
+         *       <item>@string/daltonizer_mode_deuteranomaly</item> = 12
+         * - <item>@string/daltonizer_mode_tritanomaly</item> = 13
          *
          * @hide
          */
@@ -6195,7 +6198,8 @@
                 "accessibility_display_daltonizer";
 
         private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR =
-                new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "12"});
+                new SettingsValidators.DiscreteValueValidator(
+                        new String[] {"-1", "0", "11", "12", "13"});
 
         /**
          * Setting that specifies whether automatic click when the mouse pointer stops moving is
@@ -11191,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
@@ -11506,7 +11524,14 @@
 
         /**
          * The packages whitelisted to be run in autofill compatibility mode. The list
-         * of packages is ":" colon delimited.
+         * of packages is {@code ":"} colon delimited, and each entry has the name of the
+         * package and an optional list of url bar resource ids (the list is delimited by
+         * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+         *
+         * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+         * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+         * have 2 ids {@code url_foo} and {@code url_bas}) would be
+         * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
          *
          * @hide
          */
@@ -11564,7 +11589,8 @@
             BLUETOOTH_ON,
             PRIVATE_DNS_MODE,
             PRIVATE_DNS_SPECIFIER,
-            SOFT_AP_TIMEOUT_ENABLED
+            SOFT_AP_TIMEOUT_ENABLED,
+            ZEN_DURATION,
         };
 
         /**
@@ -11605,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/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 70c4ec0..de23455 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,7 +32,6 @@
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -79,7 +78,7 @@
     private final String mSettingsActivity;
 
     @Nullable
-    private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;
+    private final ArrayMap<String, Long> mCompatibilityPackages;
 
     public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
             throws PackageManager.NameNotFoundException {
@@ -117,7 +116,7 @@
         }
 
         String settingsActivity = null;
-        ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
+        ArrayMap<String, Long> compatibilityPackages = null;
 
         try {
             final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -153,10 +152,9 @@
         mCompatibilityPackages = compatibilityPackages;
     }
 
-    private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
-            Resources resources)
-            throws IOException, XmlPullParserException {
-        ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
+    private ArrayMap<String, Long> parseCompatibilityPackages(XmlPullParser parser,
+            Resources resources) throws IOException, XmlPullParserException {
+        ArrayMap<String, Long> compatibilityPackages = null;
 
         final int outerDepth = parser.getDepth();
         int type;
@@ -200,13 +198,18 @@
                     } else {
                         maxVersionCode = Long.MAX_VALUE;
                     }
-                    final String urlBarResourceId = cpAttributes.getString(
-                            R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+                    if (true) { // TODO(b/74445943): remove block after P DP2 is branched
+                        final String urlBarResourceId = cpAttributes.getString(
+                                R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+                        if (urlBarResourceId != null) {
+                            Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'");
+                        }
+                    }
 
                     if (compatibilityPackages == null) {
                         compatibilityPackages = new ArrayMap<>();
                     }
-                    compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
+                    compatibilityPackages.put(name, maxVersionCode);
                 } finally {
                     XmlUtils.skipCurrentTag(parser);
                     if (cpAttributes != null) {
@@ -228,23 +231,10 @@
         return mSettingsActivity;
     }
 
-    public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
+    public ArrayMap<String, Long> getCompatibilityPackages() {
         return mCompatibilityPackages;
     }
 
-    /**
-     * Gets the resource id of the URL bar for a package. Used in compat mode
-     */
-    // TODO: return a list of strings instead
-    @Nullable
-    public String getUrlBarResourceId(String packageName) {
-        if (mCompatibilityPackages == null) {
-            return null;
-        }
-        final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
-        return pair == null ? null : pair.second;
-    }
-
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index eebd22a..ea10ae7 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -149,13 +149,19 @@
     /**
      * Whether notification suppressed by DND should not interruption visually when the screen is
      * off.
+     *
+     * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
      */
+    @Deprecated
     public static final int SUPPRESSED_EFFECT_SCREEN_OFF =
             NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
     /**
      * Whether notification suppressed by DND should not interruption visually when the screen is
      * on.
+     *
+     * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
      */
+    @Deprecated
     public static final int SUPPRESSED_EFFECT_SCREEN_ON =
             NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 
@@ -1453,7 +1459,8 @@
 
         /**
          * Returns the type(s) of visual effects that should be suppressed for this notification.
-         * See {@link #SUPPRESSED_EFFECT_SCREEN_OFF}, {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
+         * See {@link NotificationManager.Policy}, e.g.
+         * {@link NotificationManager.Policy#SUPPRESSED_EFFECT_LIGHTS}.
          */
         public int getSuppressedVisualEffects() {
             return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index b61919e..740a387 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -92,10 +92,12 @@
     private static final boolean DEFAULT_ALLOW_REMINDERS = false;
     private static final boolean DEFAULT_ALLOW_EVENTS = false;
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
-    private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
-    private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
+    private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
+    private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
+    private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
+            Policy.getAllSuppressedVisualEffects();
 
-    public static final int XML_VERSION = 4;
+    public static final int XML_VERSION = 5;
     public static final String ZEN_TAG = "zen";
     private static final String ZEN_ATT_VERSION = "version";
     private static final String ZEN_ATT_USER = "user";
@@ -113,6 +115,8 @@
     private static final String ALLOW_ATT_EVENTS = "events";
     private static final String ALLOW_ATT_SCREEN_OFF = "visualScreenOff";
     private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn";
+    private static final String DISALLOW_TAG = "disallow";
+    private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
 
     private static final String CONDITION_ATT_ID = "id";
     private static final String CONDITION_ATT_SUMMARY = "summary";
@@ -146,6 +150,7 @@
     public int allowCallsFrom = DEFAULT_SOURCE;
     public int allowMessagesFrom = DEFAULT_SOURCE;
     public int user = UserHandle.USER_SYSTEM;
+    public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
     public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
     public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
     public int version;
@@ -180,6 +185,7 @@
         allowAlarms = source.readInt() == 1;
         allowMedia = source.readInt() == 1;
         allowSystem = source.readInt() == 1;
+        suppressedVisualEffects = source.readInt();
     }
 
     @Override
@@ -212,6 +218,7 @@
         dest.writeInt(allowAlarms ? 1 : 0);
         dest.writeInt(allowMedia ? 1 : 0);
         dest.writeInt(allowSystem ? 1 : 0);
+        dest.writeInt(suppressedVisualEffects);
     }
 
     @Override
@@ -230,6 +237,7 @@
                 .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
                 .append(",allowWhenScreenOff=").append(allowWhenScreenOff)
                 .append(",allowWhenScreenOn=").append(allowWhenScreenOn)
+                .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
                 .append(",automaticRules=").append(automaticRules)
                 .append(",manualRule=").append(manualRule)
                 .append(']').toString();
@@ -279,6 +287,10 @@
         if (allowWhenScreenOn != to.allowWhenScreenOn) {
             d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
         }
+        if (suppressedVisualEffects != to.suppressedVisualEffects) {
+            d.addLine("suppressedVisualEffects", suppressedVisualEffects,
+                    to.suppressedVisualEffects);
+        }
         final ArraySet<String> allRules = new ArraySet<>();
         addKeys(allRules, automaticRules);
         addKeys(allRules, to.automaticRules);
@@ -383,7 +395,8 @@
                 && other.allowWhenScreenOn == allowWhenScreenOn
                 && other.user == user
                 && Objects.equals(other.automaticRules, automaticRules)
-                && Objects.equals(other.manualRule, manualRule);
+                && Objects.equals(other.manualRule, manualRule)
+                && other.suppressedVisualEffects == suppressedVisualEffects;
     }
 
     @Override
@@ -391,7 +404,8 @@
         return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
                 allowRepeatCallers, allowMessages,
                 allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
-                allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule);
+                allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+                suppressedVisualEffects);
     }
 
     private static String toDayList(int[] days) {
@@ -474,6 +488,8 @@
                         rt.allowCallsFrom = DEFAULT_SOURCE;
                         rt.allowMessagesFrom = DEFAULT_SOURCE;
                     }
+                    // continue to read even though we now have suppressedVisualEffects, in case
+                    // we need to revert to users' previous settings
                     rt.allowWhenScreenOff =
                             safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
                     rt.allowWhenScreenOn =
@@ -482,6 +498,9 @@
                     rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
                             DEFAULT_ALLOW_MEDIA);
                     rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
+                } else if (DISALLOW_TAG.equals(tag)) {
+                    rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
+                            DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
                 } else if (MANUAL_TAG.equals(tag)) {
                     rt.manualRule = readRuleXml(parser);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
@@ -517,6 +536,10 @@
         out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
         out.endTag(null, ALLOW_TAG);
 
+        out.startTag(null, DISALLOW_TAG);
+        out.attribute(null, DISALLOW_ATT_VISUAL_EFFECTS, Integer.toString(suppressedVisualEffects));
+        out.endTag(null, DISALLOW_TAG);
+
         if (manualRule != null) {
             out.startTag(null, MANUAL_TAG);
             writeRuleXml(manualRule, out);
@@ -701,13 +724,6 @@
         if (allowRepeatCallers) {
             priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
         }
-        int suppressedVisualEffects = 0;
-        if (!allowWhenScreenOff) {
-            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
-        }
-        if (!allowWhenScreenOn) {
-            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
-        }
         if (allowAlarms) {
             priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
         }
@@ -770,10 +786,7 @@
         allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders,
                 allowMessagesFrom);
         if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
-            allowWhenScreenOff =
-                    (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_OFF) == 0;
-            allowWhenScreenOn =
-                    (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
+            suppressedVisualEffects = policy.suppressedVisualEffects;
         }
     }
 
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 2c8c4ec..88e29b0 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -33,7 +33,9 @@
 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;
 import android.view.textclassifier.TextLinks;
 import android.view.textclassifier.TextSelection;
@@ -47,7 +49,7 @@
  * {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process.
  *
  * <p>See: {@link TextClassifier}.
- * See: {@link android.view.textclassifier.TextClassificationManager}.
+ * See: {@link TextClassificationManager}.
  *
  * <p>Include the following in the manifest:
  *
@@ -170,6 +172,12 @@
                         }
                     });
         }
+
+        /** {@inheritDoc} */
+        @Override
+        public void onSelectionEvent(SelectionEvent event) throws RemoteException {
+            TextClassifierService.this.onSelectionEvent(event);
+        }
     };
 
     @Nullable
@@ -237,6 +245,27 @@
             @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}.
+     */
+    public final TextClassifier getLocalTextClassifier() {
+        final TextClassificationManager tcm = getSystemService(TextClassificationManager.class);
+        if (tcm != null) {
+            return tcm.getTextClassifier(TextClassifier.LOCAL);
+        }
+        return TextClassifier.NO_OP;
+    }
+
+    /**
      * Callbacks for TextClassifierService results.
      *
      * @param <T> the type of the result
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index facf575..75cdd49 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -109,9 +109,14 @@
      */
     public final WindowConfiguration windowConfiguration;
 
+    /**
+     * Whether the task is not presented in Recents UI.
+     */
+    public boolean isNotInRecents;
+
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
-            Rect sourceContainerBounds, WindowConfiguration windowConfig) {
+            Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
@@ -122,6 +127,7 @@
         this.position = new Point(position);
         this.sourceContainerBounds = new Rect(sourceContainerBounds);
         this.windowConfiguration = windowConfig;
+        this.isNotInRecents = isNotInRecents;
     }
 
     public RemoteAnimationTarget(Parcel in) {
@@ -135,6 +141,7 @@
         position = in.readParcelable(null);
         sourceContainerBounds = in.readParcelable(null);
         windowConfiguration = in.readParcelable(null);
+        isNotInRecents = in.readBoolean();
     }
 
     @Override
@@ -154,6 +161,7 @@
         dest.writeParcelable(position, 0 /* flags */);
         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
         dest.writeParcelable(windowConfiguration, 0 /* flags */);
+        dest.writeBoolean(isNotInRecents);
     }
 
     public static final Creator<RemoteAnimationTarget> CREATOR
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 8830c90..d3b1e5c 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -396,7 +396,44 @@
         synchronized (mLock) {
             checkNotReleasedLocked();
             if (mHwuiContext == null) {
-                mHwuiContext = new HwuiContext();
+                mHwuiContext = new HwuiContext(false);
+            }
+            return mHwuiContext.lockCanvas(
+                    nativeGetWidth(mNativeObject),
+                    nativeGetHeight(mNativeObject));
+        }
+    }
+
+    /**
+     * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut.
+     *
+     * After drawing into the provided {@link Canvas}, the caller must
+     * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+     *
+     * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()},
+     * this will return a hardware-accelerated canvas that supports wide color gamut.
+     * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+     * unsupported drawing operations</a> for a list of what is and isn't
+     * supported in a hardware-accelerated canvas. It is also required to
+     * fully cover the surface every time {@link #lockHardwareCanvas()} is
+     * called as the buffer is not preserved between frames. Partial updates
+     * are not supported.
+     *
+     * @return A canvas for drawing into the surface.
+     *
+     * @throws IllegalStateException If the canvas cannot be locked.
+     *
+     * @hide
+     */
+    public Canvas lockHardwareWideColorGamutCanvas() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) {
+                mHwuiContext.destroy();
+                mHwuiContext = null;
+            }
+            if (mHwuiContext == null) {
+                mHwuiContext = new HwuiContext(true);
             }
             return mHwuiContext.lockCanvas(
                     nativeGetWidth(mNativeObject),
@@ -829,11 +866,14 @@
         private final RenderNode mRenderNode;
         private long mHwuiRenderer;
         private DisplayListCanvas mCanvas;
+        private final boolean mIsWideColorGamut;
 
-        HwuiContext() {
+        HwuiContext(boolean isWideColorGamut) {
             mRenderNode = RenderNode.create("HwuiCanvas", null);
             mRenderNode.setClipToBounds(false);
-            mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
+            mIsWideColorGamut = isWideColorGamut;
+            mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
+                    isWideColorGamut);
         }
 
         Canvas lockCanvas(int width, int height) {
@@ -864,9 +904,13 @@
                 mHwuiRenderer = 0;
             }
         }
+
+        boolean isWideColorGamut() {
+            return mIsWideColorGamut;
+        }
     }
 
-    private static native long nHwuiCreate(long rootNode, long surface);
+    private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
     private static native void nHwuiSetSurface(long renderer, long surface);
     private static native void nHwuiDraw(long renderer);
     private static native void nHwuiDestroy(long renderer);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4a9da4a..7213923 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
@@ -877,31 +876,6 @@
         return callbacks;
     }
 
-    /**
-     * This method still exists only for compatibility reasons because some applications have relied
-     * on this method via reflection. See Issue 36345857 for details.
-     *
-     * @deprecated No platform code is using this method anymore.
-     * @hide
-     */
-    @Deprecated
-    public void setWindowType(int type) {
-        if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
-            throw new UnsupportedOperationException(
-                    "SurfaceView#setWindowType() has never been a public API.");
-        }
-
-        if (type == TYPE_APPLICATION_PANEL) {
-            Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
-                    + "just to make the SurfaceView to be placed on top of its window, you must "
-                    + "call setZOrderOnTop(true) instead.", new Throwable());
-            setZOrderOnTop(true);
-            return;
-        }
-        Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
-                + "type=" + type, new Throwable());
-    }
-
     private void runOnUiThread(Runnable runnable) {
         Handler handler = getHandler();
         if (handler != null && handler.getLooper() != Looper.myLooper()) {
diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/DefaultLogger.java
similarity index 99%
rename from core/java/android/view/textclassifier/logging/DefaultLogger.java
rename to core/java/android/view/textclassifier/DefaultLogger.java
index f510879..b2f4e39 100644
--- a/core/java/android/view/textclassifier/logging/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/DefaultLogger.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
 
 import android.annotation.NonNull;
 import android.content.Context;
diff --git a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
similarity index 97%
rename from core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
rename to core/java/android/view/textclassifier/GenerateLinksLogger.java
index fb6f205..73cf43b 100644
--- a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
 
 import android.annotation.Nullable;
 import android.metrics.LogMaker;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/Logger.java
similarity index 97%
rename from core/java/android/view/textclassifier/logging/Logger.java
rename to core/java/android/view/textclassifier/Logger.java
index 4448b2b..9c92fd4 100644
--- a/core/java/android/view/textclassifier/logging/Logger.java
+++ b/core/java/android/view/textclassifier/Logger.java
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.content.Context;
 import android.util.Log;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextSelection;
 
 import com.android.internal.util.Preconditions;
 
@@ -97,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/logging/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
similarity index 70%
rename from core/java/android/view/textclassifier/logging/SelectionEvent.java
rename to core/java/android/view/textclassifier/SelectionEvent.java
index a8de308..7ac094e 100644
--- a/core/java/android/view/textclassifier/logging/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
 
 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 ec40fdd..887bebb 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -28,7 +28,6 @@
 import android.os.Parcelable;
 import android.util.ArraySet;
 import android.util.Slog;
-import android.view.textclassifier.logging.Logger;
 
 import com.android.internal.util.Preconditions;
 
@@ -324,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 41f1c69..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;
@@ -34,9 +35,6 @@
 import android.provider.Browser;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
-import android.view.textclassifier.logging.DefaultLogger;
-import android.view.textclassifier.logging.GenerateLinksLogger;
-import android.view.textclassifier.logging.Logger;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -45,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;
@@ -81,7 +78,6 @@
 
     private final Context mContext;
     private final TextClassifier mFallback;
-
     private final GenerateLinksLogger mGenerateLinksLogger;
 
     private final Object mLock = new Object();
@@ -94,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;
 
@@ -109,6 +105,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextSelection suggestSelection(
             @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
             @Nullable TextSelection.Options options) {
@@ -172,6 +169,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextClassification classifyText(
             @NonNull CharSequence text, int startIndex, int endIndex,
             @Nullable TextClassification.Options options) {
@@ -207,6 +205,7 @@
 
     /** @inheritDoc */
     @Override
+    @WorkerThread
     public TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
         Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
@@ -285,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/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1d1fcc9..61a5873 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -863,7 +863,7 @@
         }
 
         final int range = getMax() - getMin();
-        progress += scale * range;
+        progress += scale * range + getMin();
 
         setHotspot(x, y);
         setProgressInternal(Math.round(progress), true, false);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fe49c02..92285c7 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.R;
+import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -37,6 +38,7 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
@@ -99,6 +101,7 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.LinearInterpolator;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
@@ -200,11 +203,11 @@
 
     private final boolean mHapticTextHandleEnabled;
 
-    private final Magnifier mMagnifier;
+    private final MagnifierMotionAnimator mMagnifierAnimator;
     private final Runnable mUpdateMagnifierRunnable = new Runnable() {
         @Override
         public void run() {
-            mMagnifier.update();
+            mMagnifierAnimator.update();
         }
     };
     // Update the magnifier contents whenever anything in the view hierarchy is updated.
@@ -215,7 +218,7 @@
             new ViewTreeObserver.OnDrawListener() {
         @Override
         public void onDraw() {
-            if (mMagnifier != null) {
+            if (mMagnifierAnimator != null) {
                 // Posting the method will ensure that updating the magnifier contents will
                 // happen right after the rendering of the current frame.
                 mTextView.post(mUpdateMagnifierRunnable);
@@ -371,7 +374,9 @@
         mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_enableHapticTextHandle);
 
-        mMagnifier = FLAG_USE_MAGNIFIER ? new Magnifier(mTextView) : null;
+        if (FLAG_USE_MAGNIFIER) {
+            mMagnifierAnimator = new MagnifierMotionAnimator(new Magnifier(mTextView));
+        }
     }
 
     ParcelableParcel saveInstanceState() {
@@ -4309,6 +4314,88 @@
         }
     }
 
+    private static class MagnifierMotionAnimator {
+        private static final long DURATION = 100 /* miliseconds */;
+
+        // The magnifier being animated.
+        private final Magnifier mMagnifier;
+        // A value animator used to animate the magnifier.
+        private final ValueAnimator mAnimator;
+
+        // Whether the magnifier is currently visible.
+        private boolean mMagnifierIsShowing;
+        // The coordinates of the magnifier when the currently running animation started.
+        private float mAnimationStartX;
+        private float mAnimationStartY;
+        // The coordinates of the magnifier in the latest animation frame.
+        private float mAnimationCurrentX;
+        private float mAnimationCurrentY;
+        // The latest coordinates the motion animator was asked to #show() the magnifier at.
+        private float mLastX;
+        private float mLastY;
+
+        private MagnifierMotionAnimator(final Magnifier magnifier) {
+            mMagnifier = magnifier;
+            // Prepare the animator used to run the motion animation.
+            mAnimator = ValueAnimator.ofFloat(0, 1);
+            mAnimator.setDuration(DURATION);
+            mAnimator.setInterpolator(new LinearInterpolator());
+            mAnimator.addUpdateListener((animation) -> {
+                // Interpolate to find the current position of the magnifier.
+                mAnimationCurrentX = mAnimationStartX
+                        + (mLastX - mAnimationStartX) * animation.getAnimatedFraction();
+                mAnimationCurrentY = mAnimationStartY
+                        + (mLastY - mAnimationStartY) * animation.getAnimatedFraction();
+                mMagnifier.show(mAnimationCurrentX, mAnimationCurrentY);
+            });
+        }
+
+        /**
+         * Shows the magnifier at a new position.
+         * If the y coordinate is different from the previous y coordinate
+         * (probably corresponding to a line jump in the text), a short
+         * animation is added to the jump.
+         */
+        private void show(final float x, final float y) {
+            final boolean startNewAnimation = mMagnifierIsShowing && y != mLastY;
+
+            if (startNewAnimation) {
+                if (mAnimator.isRunning()) {
+                    mAnimator.cancel();
+                    mAnimationStartX = mAnimationCurrentX;
+                    mAnimationStartY = mAnimationCurrentY;
+                } else {
+                    mAnimationStartX = mLastX;
+                    mAnimationStartY = mLastY;
+                }
+                mAnimator.start();
+            } else {
+                if (!mAnimator.isRunning()) {
+                    mMagnifier.show(x, y);
+                }
+            }
+            mLastX = x;
+            mLastY = y;
+            mMagnifierIsShowing = true;
+        }
+
+        /**
+         * Updates the content of the magnifier.
+         */
+        private void update() {
+            mMagnifier.update();
+        }
+
+        /**
+         * Dismisses the magnifier, or does nothing if it is already dismissed.
+         */
+        private void dismiss() {
+            mMagnifier.dismiss();
+            mAnimator.cancel();
+            mMagnifierIsShowing = false;
+        }
+    }
+
     @VisibleForTesting
     public abstract class HandleView extends View implements TextViewPositionListener {
         protected Drawable mDrawable;
@@ -4648,52 +4735,106 @@
             return 0;
         }
 
-        protected final void showMagnifier(@NonNull final MotionEvent event) {
-            if (mMagnifier == null) {
-                return;
-            }
+        /**
+         * Computes the position where the magnifier should be shown, relative to
+         * {@code mTextView}, and writes them to {@code showPosInView}. Also decides
+         * whether the magnifier should be shown or dismissed after this touch event.
+         * @return Whether the magnifier should be shown at the computed coordinates or dismissed.
+         */
+        private boolean obtainMagnifierShowCoordinates(@NonNull final MotionEvent event,
+                final PointF showPosInView) {
 
             final int trigger = getMagnifierHandleTrigger();
             final int offset;
+            final int otherHandleOffset;
             switch (trigger) {
-                case MagnifierHandleTrigger.INSERTION: // Fall through.
+                case MagnifierHandleTrigger.INSERTION:
+                    offset = mTextView.getSelectionStart();
+                    otherHandleOffset = -1;
+                    break;
                 case MagnifierHandleTrigger.SELECTION_START:
                     offset = mTextView.getSelectionStart();
+                    otherHandleOffset = mTextView.getSelectionEnd();
                     break;
                 case MagnifierHandleTrigger.SELECTION_END:
                     offset = mTextView.getSelectionEnd();
+                    otherHandleOffset = mTextView.getSelectionStart();
                     break;
                 default:
                     offset = -1;
+                    otherHandleOffset = -1;
                     break;
             }
 
             if (offset == -1) {
-                dismissMagnifier();
+                return false;
             }
 
             final Layout layout = mTextView.getLayout();
             final int lineNumber = layout.getLineForOffset(offset);
-            // Horizontally move the magnifier smoothly.
+            // Compute whether the selection handles are currently on the same line, and,
+            // in this particular case, whether the selected text is right to left.
+            final boolean sameLineSelection = otherHandleOffset != -1
+                    && lineNumber == layout.getLineForOffset(otherHandleOffset);
+            final boolean rtl = sameLineSelection
+                    && (offset < otherHandleOffset)
+                        != (getHorizontal(mTextView.getLayout(), offset)
+                            < getHorizontal(mTextView.getLayout(), otherHandleOffset));
+
+            // Horizontally move the magnifier smoothly, clamp inside the current line / selection.
             final int[] textViewLocationOnScreen = new int[2];
             mTextView.getLocationOnScreen(textViewLocationOnScreen);
-            final float xPosInView = event.getRawX() - textViewLocationOnScreen[0];
+            final float touchXInView = event.getRawX() - textViewLocationOnScreen[0];
+            float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+            float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+            if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) {
+                leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+            } else {
+                leftBound += mTextView.getLayout().getLineLeft(lineNumber);
+            }
+            if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) {
+                rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+            } else {
+                rightBound += mTextView.getLayout().getLineRight(lineNumber);
+            }
+            final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth()
+                    / mMagnifierAnimator.mMagnifier.getZoom());
+            if (touchXInView < leftBound - contentWidth / 2
+                    || touchXInView > rightBound + contentWidth / 2) {
+                // The touch is too far from the current line / selection, so hide the magnifier.
+                return false;
+            }
+            showPosInView.x = Math.max(leftBound, Math.min(rightBound, touchXInView));
+
             // Vertically snap to middle of current line.
-            final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
+            showPosInView.y = (mTextView.getLayout().getLineTop(lineNumber)
                     + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
                     + mTextView.getTotalPaddingTop() - mTextView.getScrollY();
 
-            // Make the cursor visible and stop blinking.
-            mRenderCursorRegardlessTiming = true;
-            mTextView.invalidateCursorPath();
-            suspendBlink();
+            return true;
+        }
 
-            mMagnifier.show(xPosInView, yPosInView);
+        protected final void updateMagnifier(@NonNull final MotionEvent event) {
+            if (mMagnifierAnimator == null) {
+                return;
+            }
+
+            final PointF showPosInView = new PointF();
+            final boolean shouldShow = obtainMagnifierShowCoordinates(event, showPosInView);
+            if (shouldShow) {
+                // Make the cursor visible and stop blinking.
+                mRenderCursorRegardlessTiming = true;
+                mTextView.invalidateCursorPath();
+                suspendBlink();
+                mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+            } else {
+                dismissMagnifier();
+            }
         }
 
         protected final void dismissMagnifier() {
-            if (mMagnifier != null) {
-                mMagnifier.dismiss();
+            if (mMagnifierAnimator != null) {
+                mMagnifierAnimator.dismiss();
                 mRenderCursorRegardlessTiming = false;
                 resumeBlink();
             }
@@ -4877,11 +5018,11 @@
                 case MotionEvent.ACTION_DOWN:
                     mDownPositionX = ev.getRawX();
                     mDownPositionY = ev.getRawY();
-                    showMagnifier(ev);
+                    updateMagnifier(ev);
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    showMagnifier(ev);
+                    updateMagnifier(ev);
                     break;
 
                 case MotionEvent.ACTION_UP:
@@ -5235,11 +5376,11 @@
                     // re-engages the handle.
                     mTouchWordDelta = 0.0f;
                     mPrevX = UNSET_X_VALUE;
-                    showMagnifier(event);
+                    updateMagnifier(event);
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    showMagnifier(event);
+                    updateMagnifier(event);
                     break;
 
                 case MotionEvent.ACTION_UP:
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 85f68d7..e2601dc 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -23,6 +23,7 @@
 import android.annotation.UiThread;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Outline;
@@ -34,6 +35,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
+import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.DisplayListCanvas;
 import android.view.LayoutInflater;
@@ -49,6 +51,7 @@
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
 
+import com.android.internal.R;
 import com.android.internal.util.Preconditions;
 
 /**
@@ -75,12 +78,16 @@
     private final int mWindowWidth;
     // The height of the window containing the magnifier.
     private final int mWindowHeight;
+    // The zoom applied to the view region copied to the magnifier window.
+    private final float mZoom;
     // The width of the bitmaps where the magnifier content is copied.
     private final int mBitmapWidth;
     // The height of the bitmaps where the magnifier content is copied.
     private final int mBitmapHeight;
     // The elevation of the window containing the magnifier.
     private final float mWindowElevation;
+    // The corner radius of the window containing the magnifier.
+    private final float mWindowCornerRadius;
     // The center coordinates of the content that is to be magnified.
     private final Point mCenterZoomCoords = new Point();
     // Variables holding previous states, used for detecting redundant calls and invalidation.
@@ -102,19 +109,15 @@
     public Magnifier(@NonNull View view) {
         mView = Preconditions.checkNotNull(view);
         final Context context = mView.getContext();
-        final View content = LayoutInflater.from(context).inflate(
-                com.android.internal.R.layout.magnifier, null);
-        content.findViewById(com.android.internal.R.id.magnifier_inner).setClipToOutline(true);
-        mWindowWidth = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.magnifier_width);
-        mWindowHeight = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.magnifier_height);
-        mWindowElevation = context.getResources().getDimension(
-                com.android.internal.R.dimen.magnifier_elevation);
-        final float zoomScale = context.getResources().getFloat(
-                com.android.internal.R.dimen.magnifier_zoom_scale);
-        mBitmapWidth = Math.round(mWindowWidth / zoomScale);
-        mBitmapHeight = Math.round(mWindowHeight / zoomScale);
+        final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
+        content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
+        mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
+        mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
+        mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
+        mWindowCornerRadius = getDeviceDefaultDialogCornerRadius();
+        mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
+        mBitmapWidth = Math.round(mWindowWidth / mZoom);
+        mBitmapHeight = Math.round(mWindowHeight / mZoom);
         // The view's surface coordinates will not be updated until the magnifier is first shown.
         mViewCoordinatesInSurface = new int[2];
     }
@@ -124,6 +127,21 @@
     }
 
     /**
+     * Returns the device default theme dialog corner radius attribute.
+     * We retrieve this from the device default theme to avoid
+     * using the values set in the custom application themes.
+     */
+    private float getDeviceDefaultDialogCornerRadius() {
+        final Context deviceDefaultContext =
+                new ContextThemeWrapper(mView.getContext(), R.style.Theme_DeviceDefault);
+        final TypedArray ta = deviceDefaultContext.obtainStyledAttributes(
+                new int[]{android.R.attr.dialogCornerRadius});
+        final float dialogCornerRadius = ta.getDimension(0, 0);
+        ta.recycle();
+        return dialogCornerRadius;
+    }
+
+    /**
      * Shows the magnifier on the screen.
      *
      * @param xPosInView horizontal coordinate of the center point of the magnifier source relative
@@ -176,7 +194,8 @@
             if (mWindow == null) {
                 synchronized (mLock) {
                     mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
-                            getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation,
+                            getValidViewSurface(),
+                            mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius,
                             Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
                             mCallback);
                 }
@@ -187,21 +206,6 @@
         }
     }
 
-    @Nullable
-    private Surface getValidViewSurface() {
-        // TODO: deduplicate this against the first part of #performPixelCopy
-        final Surface surface;
-        if (mView instanceof SurfaceView) {
-            surface = ((SurfaceView) mView).getHolder().getSurface();
-        } else if (mView.getViewRootImpl() != null) {
-            surface = mView.getViewRootImpl().mSurface;
-        } else {
-            surface = null;
-        }
-
-        return (surface != null && surface.isValid()) ? surface : null;
-    }
-
     /**
      * Dismisses the magnifier from the screen. Calling this on a dismissed magnifier is a no-op.
      */
@@ -226,6 +230,44 @@
         }
     }
 
+    /**
+     * @return The width of the magnifier window, in pixels.
+     */
+    public int getWidth() {
+        return mWindowWidth;
+    }
+
+    /**
+     * @return The height of the magnifier window, in pixels.
+     */
+    public int getHeight() {
+        return mWindowHeight;
+    }
+
+    /**
+     * @return The zoom applied to the magnified view region copied to the magnifier window.
+     * If the zoom is x and the magnifier window size is (width, height), the original size
+     * of the content copied in the magnifier will be (width / x, height / x).
+     */
+    public float getZoom() {
+        return mZoom;
+    }
+
+    @Nullable
+    private Surface getValidViewSurface() {
+        // TODO: deduplicate this against the first part of #performPixelCopy
+        final Surface surface;
+        if (mView instanceof SurfaceView) {
+            surface = ((SurfaceView) mView).getHolder().getSurface();
+        } else if (mView.getViewRootImpl() != null) {
+            surface = mView.getViewRootImpl().mSurface;
+        } else {
+            surface = null;
+        }
+
+        return (surface != null && surface.isValid()) ? surface : null;
+    }
+
     private void configureCoordinates(final float xPosInView, final float yPosInView) {
         // Compute the coordinates of the center of the content going to be displayed in the
         // magnifier. These are relative to the surface the content is copied from.
@@ -246,7 +288,7 @@
         // Compute the position of the magnifier window. Again, this has to be relative to the
         // surface of the magnified view, as this surface is the parent of the magnifier surface.
         final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.magnifier_offset);
+                R.dimen.magnifier_offset);
         mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
         mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset;
     }
@@ -368,7 +410,7 @@
 
         InternalPopupWindow(final Context context, final Display display,
                 final Surface parentSurface,
-                final int width, final int height, final float elevation,
+                final int width, final int height, final float elevation, final float cornerRadius,
                 final Handler handler, final Object lock, final Callback callback) {
             mDisplay = display;
             mLock = lock;
@@ -399,7 +441,8 @@
             );
             mBitmapRenderNode = createRenderNodeForBitmap(
                     "magnifier content",
-                    elevation
+                    elevation,
+                    cornerRadius
             );
 
             final DisplayListCanvas canvas = mRenderer.getRootNode().start(width, height);
@@ -417,7 +460,8 @@
             mFrameDrawScheduled = false;
         }
 
-        private RenderNode createRenderNodeForBitmap(final String name, final float elevation) {
+        private RenderNode createRenderNodeForBitmap(final String name,
+                final float elevation, final float cornerRadius) {
             final RenderNode bitmapRenderNode = RenderNode.create(name, null);
 
             // Define the position of the bitmap in the parent render node. The surface regions
@@ -427,7 +471,7 @@
             bitmapRenderNode.setElevation(elevation);
 
             final Outline outline = new Outline();
-            outline.setRoundRect(0, 0, mContentWidth, mContentHeight, 3);
+            outline.setRoundRect(0, 0, mContentWidth, mContentHeight, cornerRadius);
             outline.setAlpha(1.0f);
             bitmapRenderNode.setOutline(outline);
             bitmapRenderNode.setClipToOutline(true);
@@ -602,7 +646,7 @@
             return null;
         }
         synchronized (mWindow.mLock) {
-            return mWindow.mBitmap;
+            return Bitmap.createScaledBitmap(mWindow.mBitmap, mWindowWidth, mWindowHeight, true);
         }
     }
 
@@ -633,8 +677,8 @@
         final Resources resources = Resources.getSystem();
         final float density = resources.getDisplayMetrics().density;
         final PointF size = new PointF();
-        size.x = resources.getDimension(com.android.internal.R.dimen.magnifier_width) / density;
-        size.y = resources.getDimension(com.android.internal.R.dimen.magnifier_height) / density;
+        size.x = resources.getDimension(R.dimen.magnifier_width) / density;
+        size.y = resources.getDimension(R.dimen.magnifier_height) / density;
         return size;
     }
 
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 8e93078..be8c34c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,13 +33,13 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ActionMode;
+import android.view.textclassifier.Logger;
+import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationConstants;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextSelection;
-import android.view.textclassifier.logging.Logger;
-import android.view.textclassifier.logging.SelectionEvent;
 import android.widget.Editor.SelectionModifierCursorController;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -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/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
deleted file mode 100644
index 04d7f9b..0000000
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
-
-import java.util.Objects;
-
-public class InputMethodSubtypeHandle {
-    private final String mInputMethodId;
-    private final int mSubtypeId;
-
-    public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
-        mInputMethodId = info.getId();
-        if (subtype != null) {
-            mSubtypeId = subtype.hashCode();
-        } else {
-            mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
-        }
-    }
-
-    public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) {
-        mInputMethodId = inputMethodId;
-        mSubtypeId = subtypeId;
-    }
-
-    public String getInputMethodId() {
-        return mInputMethodId;
-    }
-
-    public int getSubtypeId() {
-        return mSubtypeId;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == null || !(o instanceof InputMethodSubtypeHandle)) {
-            return false;
-        }
-        InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o;
-        return TextUtils.equals(mInputMethodId, other.getInputMethodId())
-                && mSubtypeId == other.getSubtypeId();
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId;
-    }
-
-    @Override
-    public String toString() {
-        return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId
-            + ", mSubtypeId=" + mSubtypeId + "}";
-    }
-}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 72cd248..6c3a58c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -147,8 +147,17 @@
         }
         mStartRtc.delete(action);
         Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
-        long duration = endRtc - startRtc;
+        logAction(action, (int)(endRtc - startRtc));
+    }
+
+    /**
+     * Logs an action that has started and ended. This needs to be called from the main thread.
+     *
+     * @param action The action to end. One of the ACTION_* values.
+     * @param duration The duration of the action in ms.
+     */
+    public static void logAction(int action, int duration) {
         Log.i(TAG, "action=" + action + " latency=" + duration);
-        EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, (int) duration);
+        EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
     }
 }
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index 518cf41..b962d4f 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -78,6 +78,10 @@
             return false;
         }
 
+        return isMessaging(sbn);
+    }
+
+    public boolean isMessaging(StatusBarNotification sbn) {
         Class<? extends Notification.Style> style = sbn.getNotification().getNotificationStyle();
         if (Notification.MessagingStyle.class.equals(style)) {
             return true;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index e3b1c01..35aae15 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1784,7 +1784,8 @@
     private static Context applyDefaultTheme(Context originalContext) {
         TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
         boolean isLightTheme = a.getBoolean(0, true);
-        int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material;
+        int themeId
+                = isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault;
         a.recycle();
         return new ContextThemeWrapper(originalContext, themeId);
     }
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 5a06f7f..25e1589 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -54,13 +54,6 @@
     void userPresent(int userId);
     int getStrongAuthForUser(int userId);
 
-    long addEscrowToken(in byte[] token, int userId);
-    boolean removeEscrowToken(long handle, int userId);
-    boolean isEscrowTokenActive(long handle, int userId);
-    boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
-            in byte[] token, int requestedQuality, int userId);
-    void unlockUserWithToken(long tokenHandle, in byte[] token, int userId);
-
     // Keystore RecoveryController methods.
     // {@code ServiceSpecificException} may be thrown to signal an error, which caller can
     // convert to  {@code RecoveryManagerException}.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 7eb2f38..bf075bf 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -45,6 +45,7 @@
 import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 import com.google.android.collect.Lists;
 
 import libcore.util.HexEncoding;
@@ -1473,6 +1474,13 @@
         }
     }
 
+    private LockSettingsInternal getLockSettingsInternal() {
+        LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
+        if (service == null) {
+            throw new SecurityException("Only available to system server itself");
+        }
+        return service;
+    }
     /**
      * Create an escrow token for the current user, which can later be used to unlock FBE
      * or change user password.
@@ -1481,44 +1489,41 @@
      * confirm credential operation in order to activate the token for future use. If the user
      * has no secure lockscreen, then the token is activated immediately.
      *
+     * <p>This method is only available to code running in the system server process itself.
+     *
      * @return a unique 64-bit token handle which is needed to refer to this token later.
      */
     public long addEscrowToken(byte[] token, int userId) {
-        try {
-            return getLockSettings().addEscrowToken(token, userId);
-        } catch (RemoteException re) {
-            return 0L;
-        }
+        return getLockSettingsInternal().addEscrowToken(token, userId);
     }
 
     /**
      * Remove an escrow token.
+     *
+     * <p>This method is only available to code running in the system server process itself.
+     *
      * @return true if the given handle refers to a valid token previously returned from
      * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
      */
     public boolean removeEscrowToken(long handle, int userId) {
-        try {
-            return getLockSettings().removeEscrowToken(handle, userId);
-        } catch (RemoteException re) {
-            return false;
-        }
+        return getLockSettingsInternal().removeEscrowToken(handle, userId);
     }
 
     /**
      * Check if the given escrow token is active or not. Only active token can be used to call
      * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+     *
+     * <p>This method is only available to code running in the system server process itself.
      */
     public boolean isEscrowTokenActive(long handle, int userId) {
-        try {
-            return getLockSettings().isEscrowTokenActive(handle, userId);
-        } catch (RemoteException re) {
-            return false;
-        }
+        return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
     }
 
     /**
      * Change a user's lock credential with a pre-configured escrow token.
      *
+     * <p>This method is only available to code running in the system server process itself.
+     *
      * @param credential The new credential to be set
      * @param type Credential type: password / pattern / none.
      * @param requestedQuality the requested password quality by DevicePolicyManager.
@@ -1530,55 +1535,55 @@
      */
     public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
             long tokenHandle, byte[] token, int userId) {
-        try {
-            if (type != CREDENTIAL_TYPE_NONE) {
-                if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
-                    throw new IllegalArgumentException("password must not be null and at least "
-                            + "of length " + MIN_LOCK_PASSWORD_SIZE);
-                }
-                final int quality = computePasswordQuality(type, credential, requestedQuality);
-                if (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle,
-                        token, quality, userId)) {
-                    return false;
-                }
-                setLong(PASSWORD_TYPE_KEY, quality, userId);
-
-                updateEncryptionPasswordIfNeeded(credential, quality, userId);
-                updatePasswordHistory(credential, userId);
-            } else {
-                if (!TextUtils.isEmpty(credential)) {
-                    throw new IllegalArgumentException("password must be emtpy for NONE type");
-                }
-                if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
-                        tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                        userId)) {
-                    return false;
-                }
-                setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                        userId);
-
-                if (userId == UserHandle.USER_SYSTEM) {
-                    // Set the encryption password to default.
-                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
-                    setCredentialRequiredToDecrypt(false);
-                }
+        LockSettingsInternal localService = getLockSettingsInternal();
+        if (type != CREDENTIAL_TYPE_NONE) {
+            if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
+                throw new IllegalArgumentException("password must not be null and at least "
+                        + "of length " + MIN_LOCK_PASSWORD_SIZE);
             }
-            onAfterChangingPassword(userId);
-            return true;
-        } catch (RemoteException re) {
-            Log.e(TAG, "Unable to save lock password ", re);
-            re.rethrowFromSystemServer();
+            final int quality = computePasswordQuality(type, credential, requestedQuality);
+            if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
+                    token, quality, userId)) {
+                return false;
+            }
+            setLong(PASSWORD_TYPE_KEY, quality, userId);
+
+            updateEncryptionPasswordIfNeeded(credential, quality, userId);
+            updatePasswordHistory(credential, userId);
+        } else {
+            if (!TextUtils.isEmpty(credential)) {
+                throw new IllegalArgumentException("password must be emtpy for NONE type");
+            }
+            if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
+                    tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                    userId)) {
+                return false;
+            }
+            setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                    userId);
+
+            if (userId == UserHandle.USER_SYSTEM) {
+                // Set the encryption password to default.
+                updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+                setCredentialRequiredToDecrypt(false);
+            }
         }
-        return false;
+        onAfterChangingPassword(userId);
+        return true;
     }
 
-    public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
-        try {
-            getLockSettings().unlockUserWithToken(tokenHandle, token, userId);
-        } catch (RemoteException re) {
-            Log.e(TAG, "Unable to unlock user with token", re);
-            re.rethrowFromSystemServer();
-        }
+    /**
+     * Unlock the specified user by an pre-activated escrow token. This should have the same effect
+     * on device encryption as the user entering his lockscreen credentials for the first time after
+     * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
+     *
+     * <p>This method is only available to code running in the system server process itself.
+     *
+     * @return {@code true} if the supplied token is valid and unlock succeeds,
+     *         {@code false} otherwise.
+     */
+    public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+        return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
     }
 
 
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
new file mode 100644
index 0000000..9de9ef7
--- /dev/null
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -0,0 +1,56 @@
+/*
+ * 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.internal.widget;
+
+
+/**
+ * LockSettingsService local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class LockSettingsInternal {
+
+    /**
+     * Create an escrow token for the current user, which can later be used to unlock FBE
+     * or change user password.
+     *
+     * After adding, if the user currently has lockscreen password, he will need to perform a
+     * confirm credential operation in order to activate the token for future use. If the user
+     * has no secure lockscreen, then the token is activated immediately.
+     *
+     * @return a unique 64-bit token handle which is needed to refer to this token later.
+     */
+    public abstract long addEscrowToken(byte[] token, int userId);
+
+    /**
+     * Remove an escrow token.
+     * @return true if the given handle refers to a valid token previously returned from
+     * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
+     */
+    public abstract boolean removeEscrowToken(long handle, int userId);
+
+    /**
+     * Check if the given escrow token is active or not. Only active token can be used to call
+     * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+     */
+    public abstract boolean isEscrowTokenActive(long handle, int userId);
+
+    public abstract boolean setLockCredentialWithToken(String credential, int type,
+            long tokenHandle, byte[] token, int requestedQuality, int userId);
+
+    public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
+}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8b1de2f..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,16 +277,20 @@
         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(
                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
 
-        // Allow ODM to customize system configs around libs, features and apps
-        int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
+        // Allow ODM to customize system configs as much as Vendor, because /odm is another
+        // vendor partition other than /vendor.
+        int odmPermissionFlag = vendorPermissionFlag;
         readPermissions(Environment.buildPath(
                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
         readPermissions(Environment.buildPath(
@@ -631,7 +636,9 @@
                     // granting permissions to priv apps in the system partition and vice
                     // versa.
                     boolean vendor = permFile.toPath().startsWith(
-                            Environment.getVendorDirectory().toPath());
+                            Environment.getVendorDirectory().toPath())
+                            || permFile.toPath().startsWith(
+                                Environment.getOdmDirectory().toPath());
                     boolean product = permFile.toPath().startsWith(
                             Environment.getProductDirectory().toPath());
                     if (vendor) {
@@ -656,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
new file mode 100644
index 0000000..3d3a3d0
--- /dev/null
+++ b/core/java/com/android/server/net/BaseNetdEventCallback.java
@@ -0,0 +1,38 @@
+/*
+ * 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.net;
+
+import android.net.INetdEventCallback;
+
+/**
+ * Base {@link INetdEventCallback} that provides no-op
+ * implementations which can be overridden.
+ *
+ * @hide
+ */
+public class BaseNetdEventCallback extends INetdEventCallback.Stub {
+    @Override
+    public void onDnsEvent(String hostname, String[] ipAddresses,
+            int ipAddressesCount, long timestamp, int uid) {
+        // 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/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f5c09fd..f70cf07 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -546,12 +546,16 @@
     }
 };
 
-static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr) {
+static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr,
+        jboolean isWideColorGamut) {
     RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
     sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
     ContextFactory factory;
     RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
     proxy->loadSystemProperties();
+    if (isWideColorGamut) {
+        proxy->setWideGamut(true);
+    }
     proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
@@ -620,7 +624,7 @@
     {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
 
     // HWUI context
-    {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
+    {"nHwuiCreate", "(JJZ)J", (void*) hwui::create },
     {"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface },
     {"nHwuiDraw", "(J)V", (void*) hwui::draw },
     {"nHwuiDestroy", "(J)V", (void*) hwui::destroy },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d6fe568..d05be2c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -488,6 +488,8 @@
   if (errno != 0) {
     ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
   }
+  // Update base::logging default tag.
+  android::base::SetDefaultTag(buf);
 }
 
 // The list of open zygote file descriptors.
@@ -685,10 +687,10 @@
 
     // Make it easier to debug audit logs by setting the main thread's name to the
     // nice name rather than "app_process".
-    if (se_info_c_str == NULL && is_system_server) {
+    if (se_name_c_str == NULL && is_system_server) {
       se_name_c_str = "system_server";
     }
-    if (se_info_c_str != NULL) {
+    if (se_name_c_str != NULL) {
       SetThreadName(se_name_c_str);
     }
 
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 9915174..f468143 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -641,9 +641,7 @@
   message Job {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional string name = 1 [
-        (android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string name = 1;
     // Job times aren't apportioned.
     optional TimerProto total = 2;
     optional TimerProto background = 3;
@@ -654,9 +652,7 @@
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Job name.
-    optional string name = 1 [
-        (android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string name = 1;
 
     message ReasonCount {
       option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -801,9 +797,7 @@
   message Sync {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional string name = 1 [
-        (android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string name = 1;
     // Sync times aren't apportioned.
     optional TimerProto total = 2;
     optional TimerProto background = 3;
@@ -842,9 +836,7 @@
   message Wakelock {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional string name = 1 [
-        (android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string name = 1;
 
     // Full wakelocks keep the screen on. Based on
     // PowerManager.SCREEN_BRIGHT_WAKE_LOCK (deprecated in API 13) and
@@ -876,9 +868,7 @@
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Wakeup alarm name.
-    optional string name = 1 [
-        (android.privacy).dest = DEST_EXPLICIT
-    ];
+    optional string name = 1;
     // Only includes counts when screen-off (& on battery).
     optional int32 count = 2;
   }
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/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 69abed3..9193129 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -614,7 +614,6 @@
         CONSTRAINT_DEADLINE = 5;
         CONSTRAINT_IDLE = 6;
         CONSTRAINT_CONNECTIVITY = 7;
-        CONSTRAINT_APP_NOT_IDLE = 8;
         CONSTRAINT_CONTENT_TRIGGER = 9;
         CONSTRAINT_DEVICE_NOT_DOZING = 10;
     }
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 5cb5319..64aa98b 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -315,4 +315,6 @@
     optional bool is_double_tap_wake_enabled = 37;
     // True if we are currently in VR Mode.
     optional bool is_vr_mode_enabled = 38;
+    // True if Sidekick is controlling the display and we shouldn't change its power mode.
+    optional bool draw_wake_lock_override_from_sidekick = 39;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7aec812..f521e4b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -56,6 +56,7 @@
     <protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.BATTERY_LEVEL_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
     <protected-broadcast android:name="android.intent.action.BATTERY_OKAY" />
     <protected-broadcast android:name="android.intent.action.ACTION_POWER_CONNECTED" />
diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background_dark.xml
index ded1137..c4b4448 100644
--- a/core/res/res/drawable/floating_popup_background_dark.xml
+++ b/core/res/res/drawable/floating_popup_background_dark.xml
@@ -16,8 +16,8 @@
 */
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
+    android:shape="rectangle">
     <solid android:color="@color/background_floating_material_dark" />
-    <corners android:radius="2dp" />
+    <corners android:radius="?android:attr/dialogCornerRadius" />
 </shape>
 
diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background_light.xml
index 9c7a886..767140d 100644
--- a/core/res/res/drawable/floating_popup_background_light.xml
+++ b/core/res/res/drawable/floating_popup_background_light.xml
@@ -18,6 +18,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
     <solid android:color="@color/background_floating_material_light" />
-    <corners android:radius="2dp" />
+    <corners android:radius="?android:attr/dialogCornerRadius" />
 </shape>
 
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 b81a74d..4a72bf9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7981,9 +7981,7 @@
              android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
         -->
         <attr name="maxLongVersionCode" format="string" />
-        <!-- The resource id of view that contains the URL bar of the HTML page being loaded.
-             Typically used when compatibility mode is used in a browser.
-        -->
+        <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
         <attr name="urlBarResourceId" format="string" />
     </declare-styleable>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f1c9f67..cf13d1c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2396,6 +2396,7 @@
         <!-- depends on ImportanceExtractor-->
         <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
         <item>com.android.server.notification.VisibilityExtractor</item>
+        <!-- Depends on ZenModeExtractor -->
         <item>com.android.server.notification.BadgeExtractor</item>
 
     </string-array>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7d5d1ba..2c0deed 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
       <public name="outlineSpotShadowColor" />
       <public name="outlineAmbientShadowColor" />
       <public name="maxLongVersionCode" />
+      <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
       <public name="urlBarResourceId" />
       <!-- @hide @SystemApi -->
       <public name="userRestriction" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 15dffc0..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>
 
@@ -4883,7 +4883,7 @@
     <!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
     <string name="notification_channel_system_changes">System changes</string>
     <!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
-    <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+    <string name="zen_upgrade_notification_title">Do Not Disturb is hiding notifications to help you focus</string>
     <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
-    <string name="zen_upgrade_notification_content">Tap to check your behavior settings for interruptions</string>
+    <string name="zen_upgrade_notification_content">This is a new feature from the latest system update. Tap to change.</string>
 </resources>
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/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 5e463d8..2d3cd1c 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,9 @@
 -->
 
 <!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
-<zen version="4">
+<zen version="5">
     <allow alarms="true" media="true" system="false" calls="false" messages="false" reminders="false"
            events="false" />
+    <!-- all visual effects that exist as of P -->
+    <disallow suppressedVisualEffect="511" />
 </zen>
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/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/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/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index b920ca3..8e4f02c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -26,6 +26,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
+import android.view.textclassifier.GenerateLinksLogger;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
 
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/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index 1d46d42..fd1027c 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -67,6 +67,7 @@
   <hidden-api-whitelisted-app package="com.android.pacprocessor" />
   <hidden-api-whitelisted-app package="com.android.phone" />
   <hidden-api-whitelisted-app package="com.android.pmc" />
+  <hidden-api-whitelisted-app package="com.android.printspooler" />
   <hidden-api-whitelisted-app package="com.android.providers.blockednumber" />
   <hidden-api-whitelisted-app package="com.android.providers.contacts" />
   <hidden-api-whitelisted-app package="com.android.providers.downloads" />
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 813eae7..35790b6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -6,10 +6,7 @@
         //"hwui_bugreport_font_cache_usage",
         //"hwui_compile_for_perf",
         "hwui_pgo",
-        // Disable LTO temporarily.  LTO does not seem to interact well with
-        // PGO profile-file updates and incremental builds in the build
-        // servers.
-        // "hwui_lto",
+        "hwui_lto",
     ],
 
     cpp_std: "c++17",
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 44d9099..3dd6879 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3002,6 +3002,7 @@
         // from OMX_VIDEO_HEVCPROFILETYPE
         public static final int HEVCProfileMain        = 0x01;
         public static final int HEVCProfileMain10      = 0x02;
+        public static final int HEVCProfileMainStill   = 0x04;
         public static final int HEVCProfileMain10HDR10 = 0x1000;
 
         // from OMX_VIDEO_HEVCLEVELTYPE
@@ -3078,6 +3079,23 @@
          * {@link VideoCapabilities} to determine the codec capabilities.
          */
         public int level;
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (obj instanceof CodecProfileLevel) {
+                CodecProfileLevel other = (CodecProfileLevel)obj;
+                return other.profile == profile && other.level == level;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Long.hashCode(((long)profile << Integer.SIZE) | level);
+        }
     };
 
     /**
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 b2b609e..1c4d898 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -80,6 +80,7 @@
 import java.util.UUID;
 import java.util.Vector;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
@@ -102,8 +103,6 @@
     private boolean mScreenOnWhilePlaying;
     private boolean mStayAwake;
     private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
-    private int mUsage = -1;
-    private boolean mBypassInterruptionPolicy;
     private final CloseGuard mGuard = CloseGuard.get();
 
     private final Object mSrcLock = new Object();
@@ -117,6 +116,9 @@
     private boolean mNextSourcePlayPending = false;
     //--- guarded by |mSrcLock| end
 
+    private AtomicInteger mBufferedPercentageCurrent;
+    private AtomicInteger mBufferedPercentageNext;
+
     // Modular DRM
     private final Object mDrmLock = new Object();
     //--- guarded by |mDrmLock| start
@@ -211,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;
@@ -239,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();
@@ -262,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;
@@ -275,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
+            }
+        });
     }
 
     /**
@@ -306,9 +308,8 @@
      */
     @Override
     public long getBufferedPosition() {
-        // TODO: either get buffered position from native code, or cache BUFFERING_UPDATE
-        // number and convert it to buffered position.
-        return 0;
+        // Use cached buffered percent for now.
+        return getDuration() * mBufferedPercentageCurrent.get() / 100;
     }
 
     @Override
@@ -356,17 +357,19 @@
      */
     @Override
     public void setAudioAttributes(@NonNull AudioAttributes attributes) {
-        if (attributes == null) {
-            final String msg = "Cannot set AudioAttributes to null";
-            throw new IllegalArgumentException(msg);
-        }
-        mUsage = attributes.getUsage();
-        mBypassInterruptionPolicy = (attributes.getAllFlags()
-                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
-        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
@@ -386,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) {
+                    }
+                }
             }
-        }
+        });
     }
 
     /**
@@ -408,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();
+                    }
+                }
             }
-        }
+        });
     }
 
     /**
@@ -434,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
@@ -471,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);
@@ -488,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));
+            }
+        });
     }
 
     /**
@@ -524,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);
@@ -632,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));
+                    }
+                }
+            }
+        });
     }
 
     /**
@@ -685,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();
+            }
+        });
     }
 
     /**
@@ -714,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();
+                }
+            }
+        });
     }
 
     /**
@@ -737,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) {
@@ -981,8 +1038,10 @@
             // Switch to next source only when it's in prepared state.
             mCurrentDSD = mNextDSDs.get(0);
             mCurrentSrcId = mNextSrcId;
+            mBufferedPercentageCurrent.set(mBufferedPercentageNext.get());
             mNextDSDs.remove(0);
             mNextSrcId = mSrcIdGenerator++;  // make it different from mCurrentSrcId
+            mBufferedPercentageNext.set(0);
             mNextSourceState = NEXT_SOURCE_STATE_INIT;
             mNextSourcePlayPending = false;
 
@@ -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();
                     }
@@ -2781,9 +2914,21 @@
             {
                 final int percent = msg.arg1;
                 synchronized (mEventCbLock) {
-                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE, percent));
+                    if (srcId == mCurrentSrcId) {
+                        mBufferedPercentageCurrent.set(percent);
+                        for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+                            cb.first.execute(() -> cb.second.onInfo(
+                                    mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE,
+                                    percent));
+                        }
+                    } else if (srcId == mNextSrcId && !mNextDSDs.isEmpty()) {
+                        mBufferedPercentageNext.set(percent);
+                        DataSourceDesc nextDSD = mNextDSDs.get(0);
+                        for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+                            cb.first.execute(() -> cb.second.onInfo(
+                                    mMediaPlayer, nextDSD, MEDIA_INFO_BUFFERING_UPDATE,
+                                    percent));
+                        }
                     }
                 }
                 return;
@@ -2791,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();
                     }
                 }
             }
@@ -3378,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
+        });
     }
 
 
@@ -3458,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 {
@@ -3519,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 {
@@ -3529,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;
@@ -3558,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
+        });
     }
 
 
@@ -3599,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 {
@@ -3637,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 {
@@ -4575,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/MediaScanner.java b/media/java/android/media/MediaScanner.java
index c309038..9d2c2828 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -324,7 +324,6 @@
     private final Uri mAudioUri;
     private final Uri mVideoUri;
     private final Uri mImagesUri;
-    private final Uri mThumbsUri;
     private final Uri mPlaylistsUri;
     private final Uri mFilesUri;
     private final Uri mFilesUriNoNotify;
@@ -420,7 +419,6 @@
         mAudioUri = Audio.Media.getContentUri(volumeName);
         mVideoUri = Video.Media.getContentUri(volumeName);
         mImagesUri = Images.Media.getContentUri(volumeName);
-        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
         mFilesUri = Files.getContentUri(volumeName);
         mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
 
@@ -1287,53 +1285,6 @@
         }
     }
 
-    private void pruneDeadThumbnailFiles() {
-        HashSet<String> existingFiles = new HashSet<String>();
-        String directory = "/sdcard/DCIM/.thumbnails";
-        String [] files = (new File(directory)).list();
-        Cursor c = null;
-        if (files == null)
-            files = new String[0];
-
-        for (int i = 0; i < files.length; i++) {
-            String fullPathString = directory + "/" + files[i];
-            existingFiles.add(fullPathString);
-        }
-
-        try {
-            c = mMediaProvider.query(
-                    mThumbsUri,
-                    new String [] { "_data" },
-                    null,
-                    null,
-                    null, null);
-            Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
-            if (c != null && c.moveToFirst()) {
-                do {
-                    String fullPathString = c.getString(0);
-                    existingFiles.remove(fullPathString);
-                } while (c.moveToNext());
-            }
-
-            for (String fileToDelete : existingFiles) {
-                if (false)
-                    Log.v(TAG, "fileToDelete is " + fileToDelete);
-                try {
-                    (new File(fileToDelete)).delete();
-                } catch (SecurityException ex) {
-                }
-            }
-
-            Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
-        } catch (RemoteException e) {
-            // We will soon be killed...
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-    }
-
     static class MediaBulkDeleter {
         StringBuilder whereClause = new StringBuilder();
         ArrayList<String> whereArgs = new ArrayList<String>(100);
@@ -1377,9 +1328,6 @@
             processPlayLists();
         }
 
-        if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
-            pruneDeadThumbnailFiles();
-
         // allow GC to clean up
         mPlayLists.clear();
     }
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/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 664308c..9899367 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -44,13 +44,14 @@
  */
 public class MiniThumbFile {
     private static final String TAG = "MiniThumbFile";
-    private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+    private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
     public static final int BYTES_PER_MINTHUMB = 10000;
     private static final int HEADER_SIZE = 1 + 8 + 4;
     private Uri mUri;
     private RandomAccessFile mMiniThumbFile;
     private FileChannel mChannel;
     private ByteBuffer mBuffer;
+    private ByteBuffer mEmptyBuffer;
     private static final Hashtable<String, MiniThumbFile> sThumbFiles =
         new Hashtable<String, MiniThumbFile>();
 
@@ -127,9 +128,10 @@
         return mMiniThumbFile;
     }
 
-    public MiniThumbFile(Uri uri) {
+    private MiniThumbFile(Uri uri) {
         mUri = uri;
         mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
+        mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
     }
 
     public synchronized void deactivate() {
@@ -184,6 +186,54 @@
         return 0;
     }
 
+    public synchronized void eraseMiniThumb(long id) {
+        RandomAccessFile r = miniThumbDataFile();
+        if (r != null) {
+            long pos = id * BYTES_PER_MINTHUMB;
+            FileLock lock = null;
+            try {
+                mBuffer.clear();
+                mBuffer.limit(1 + 8);
+
+                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+                // check that we can read the following 9 bytes
+                // (1 for the "status" and 8 for the long)
+                if (mChannel.read(mBuffer, pos) == 9) {
+                    mBuffer.position(0);
+                    if (mBuffer.get() == 1) {
+                        long currentMagic = mBuffer.getLong();
+                        if (currentMagic == 0) {
+                            // there is no thumbnail stored here
+                            Log.i(TAG, "no thumbnail for id " + id);
+                            return;
+                        }
+                        // zero out the thumbnail slot
+                        // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
+                        //         + " at offset " + pos);
+                        mChannel.write(mEmptyBuffer, pos);
+                    }
+                } else {
+                    // Log.v(TAG, "No slot");
+                }
+            } catch (IOException ex) {
+                Log.v(TAG, "Got exception checking file magic: ", ex);
+            } catch (RuntimeException ex) {
+                // Other NIO related exception like disk full, read only channel..etc
+                Log.e(TAG, "Got exception when reading magic, id = " + id +
+                        ", disk full or mount read-only? " + ex.getClass());
+            } finally {
+                try {
+                    if (lock != null) lock.release();
+                }
+                catch (IOException ex) {
+                    // ignore it.
+                }
+            }
+        } else {
+            // Log.v(TAG, "No data file");
+        }
+    }
+
     public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
             throws IOException {
         RandomAccessFile r = miniThumbDataFile();
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..eb03ca7f 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/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
index e6e0ad3..7dc23ff 100644
--- a/packages/CaptivePortalLogin/Android.mk
+++ b/packages/CaptivePortalLogin/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
index 2324593..c292323 100644
--- a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
+++ b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
@@ -27,12 +27,17 @@
             android:layout_height="wrap_content" />
       </FrameLayout>
 
-      <WebView
-          android:id="@+id/webview"
-          android:layout_width="match_parent"
-          android:layout_height="match_parent"
-          android:layout_alignParentBottom="false"
-          android:layout_alignParentRight="false" />
+      <android.support.v4.widget.SwipeRefreshLayout
+            android:id="@+id/swipe_refresh"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <WebView
+              android:id="@+id/webview"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout_alignParentBottom="false"
+              android:layout_alignParentRight="false" />
+      </android.support.v4.widget.SwipeRefreshLayout>
 
     </LinearLayout>
 </FrameLayout>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index e13aba7..4db0034 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -34,6 +34,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
+import android.support.v4.widget.SwipeRefreshLayout;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.TypedValue;
@@ -88,6 +89,7 @@
     private ConnectivityManager mCm;
     private boolean mLaunchBrowser = false;
     private MyWebViewClient mWebViewClient;
+    private SwipeRefreshLayout mSwipeRefreshLayout;
     // Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
     private final AtomicBoolean isDone = new AtomicBoolean(false);
 
@@ -159,6 +161,13 @@
         // Start initial page load so WebView finishes loading proxy settings.
         // Actual load of mUrl is initiated by MyWebViewClient.
         webview.loadData("", "text/html", null);
+
+        mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
+        mSwipeRefreshLayout.setOnRefreshListener(() -> {
+                webview.reload();
+                mSwipeRefreshLayout.setRefreshing(true);
+            });
+
     }
 
     // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
@@ -393,6 +402,7 @@
         public void onPageFinished(WebView view, String url) {
             mPagesLoaded++;
             getProgressBar().setVisibility(View.INVISIBLE);
+            mSwipeRefreshLayout.setRefreshing(false);
             if (mPagesLoaded == 1) {
                 // Now that WebView has loaded at least one page we know it has read in the proxy
                 // settings.  Now prompt the WebView read the Network-specific proxy settings.
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 3c2ca2d..15b50d7 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -34,21 +34,21 @@
 
 # Include support-v7-appcompat, if not already included
 ifeq (,$(findstring android-support-v7-appcompat,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
 LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
 endif
 
 # Include support-v7-recyclerview, if not already included
 ifeq (,$(findstring android-support-v7-recyclerview,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/recyclerview/res
 LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
 endif
 
 # Include android-support-v7-preference, if not already included
 ifeq (,$(findstring android-support-v7-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/preference/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/preference/res
 LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference
 endif
diff --git a/packages/SettingsLib/res/color/batterymeter_plus_color.xml b/packages/SettingsLib/res/color/batterymeter_plus_color.xml
new file mode 100644
index 0000000..949bede
--- /dev/null
+++ b/packages/SettingsLib/res/color/batterymeter_plus_color.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorError" />
+</selector>
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/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 4fe9d56..e2f279a9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -54,6 +54,7 @@
     private int mLevel = -1;
     private boolean mCharging;
     private boolean mPowerSaveEnabled;
+    private boolean mPowerSaveAsColorError = true;
     private boolean mShowPercent;
 
     private static final boolean SINGLE_DIGIT_PERCENT = false;
@@ -150,7 +151,8 @@
         mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
         mBoltPoints = loadPoints(res, R.array.batterymeter_bolt_points);
 
-        mPlusPaint = new Paint(mBoltPaint);
+        mPlusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPlusPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_plus_color));
         mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
 
         mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
@@ -195,6 +197,10 @@
         postInvalidate();
     }
 
+    protected void setPowerSaveAsColorError(boolean asError) {
+        mPowerSaveAsColorError = asError;
+    }
+
     // an approximation of View.postInvalidate()
     protected void postInvalidate() {
         unscheduleSelf(this::invalidateSelf);
@@ -254,10 +260,6 @@
     }
 
     private int getColorForLevel(int percent) {
-        // If we are in power save mode, always use the normal color.
-        if (mPowerSaveEnabled) {
-            return mIconTint;
-        }
         int thresh, color = 0;
         for (int i = 0; i < mColors.length; i += 2) {
             thresh = mColors[i];
@@ -279,7 +281,6 @@
         mIconTint = fillColor;
         mFramePaint.setColor(backgroundColor);
         mBoltPaint.setColor(fillColor);
-        mPlusPaint.setColor(fillColor);
         mChargeColor = fillColor;
         invalidateSelf();
     }
@@ -392,14 +393,16 @@
                         mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
             }
 
-            float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
-            boltPct = Math.min(Math.max(boltPct, 0), 1);
-            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
-                // draw the bolt if opaque
+            float fillPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+            fillPct = Math.min(Math.max(fillPct, 0), 1);
+            if (fillPct <= BOLT_LEVEL_THRESHOLD) {
+                // draw the plus if opaque
                 c.drawPath(mPlusPath, mPlusPaint);
             } else {
-                // otherwise cut the bolt out of the overall shape
                 mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+                if (mPowerSaveAsColorError) {
+                    c.drawPath(mPlusPath, mPlusPaint);
+                }
             }
         }
 
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/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/StatementService/src/com/android/statementservice/DirectStatementService.java b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
index 449738e..659696e 100644
--- a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
+++ b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
@@ -155,17 +155,20 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
-        if (mThread != null) {
-            mThread.quit();
-        }
-
-        try {
-            if (mHttpResponseCache != null) {
-                mHttpResponseCache.delete();
+        final HttpResponseCache responseCache = mHttpResponseCache;
+        mHandler.post(new Runnable() {
+            public void run() {
+                try {
+                    if (responseCache != null) {
+                        responseCache.delete();
+                    }
+                } catch (IOException e) {
+                    Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
+                }
+                Looper.myLooper().quit();
             }
-        } catch (IOException e) {
-            Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
-        }
+        });
+        mHttpResponseCache = null;
     }
 
     @Override
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 828c9df..611aa43 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_marginStart="16dp"
     android:layout_marginEnd="16dp"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:clipToPadding="false"
@@ -37,7 +37,8 @@
               android:textColor="?attr/wallpaperTextColor"
               android:theme="@style/TextAppearance.Keyguard"
     />
-    <LinearLayout android:id="@+id/row"
+    <view class="com.android.keyguard.KeyguardSliceView$Row"
+              android:id="@+id/row"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal"
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml
deleted file mode 100644
index 57b61da..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
-    Copyright (C) 2015 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/linear_interpolator"
-    android:duration="@integer/carrier_network_change_anim_time"
-    android:repeatCount="-1">
-
-    <propertyValuesHolder
-        android:propertyName="fillColor"
-        android:valueType="colorType">
-        <keyframe
-            android:fraction="0.0"
-            android:value="#FFFFFFFF"/>
-        <keyframe
-            android:fraction="0.32"
-            android:value="#FFFFFFFF"/>
-        <keyframe
-            android:fraction="0.33"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="1.0"
-            android:value="#4DFFFFFF"/>
-    </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml
deleted file mode 100644
index 09694c3..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<!--
-    Copyright (C) 2015 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/linear_interpolator"
-    android:duration="@integer/carrier_network_change_anim_time"
-    android:repeatCount="-1">
-
-    <propertyValuesHolder
-        android:propertyName="fillColor"
-        android:valueType="colorType">
-        <keyframe
-            android:fraction="0.0"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="0.32"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="0.33"
-            android:value="#FFFFFFFF"/>
-        <keyframe
-            android:fraction="0.66"
-            android:value="#FFFFFFFF"/>
-        <keyframe
-            android:fraction="0.67"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="1.0"
-            android:value="#4DFFFFFF"/>
-    </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml
deleted file mode 100644
index 2270e3f..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
-    Copyright (C) 2015 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/linear_interpolator"
-    android:duration="@integer/carrier_network_change_anim_time"
-    android:repeatCount="-1">
-
-    <propertyValuesHolder
-        android:propertyName="fillColor"
-        android:valueType="colorType">
-        <keyframe
-            android:fraction="0.0"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="0.66"
-            android:value="#4DFFFFFF"/>
-        <keyframe
-            android:fraction="0.67"
-            android:value="#FFFFFFFF"/>
-        <keyframe
-            android:fraction="1.0"
-            android:value="#FFFFFFFF"/>
-    </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
new file mode 100644
index 0000000..221f170
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
@@ -0,0 +1,26 @@
+<?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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/fingerprint_dialog_bg_color" />
+    <corners android:radius="1dp"
+        android:topLeftRadius="@dimen/fingerprint_dialog_corner_size"
+        android:topRightRadius="@dimen/fingerprint_dialog_corner_size"
+        android:bottomLeftRadius="0dp"
+        android:bottomRightRadius="0dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
new file mode 100644
index 0000000..382d9d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M4,7h4v10H6V9H4V7z M15.83,11.72L18.66,7h-2.33l-1.66,2.77L13,7h-2.33l2.83,4.72L10.33,17h2.33l2-3.34l2,3.34H19 L15.83,11.72z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
new file mode 100644
index 0000000..ce003e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M3,7v2h5v2H4v2h4v2H3v2h5c1.1,0,2-0.9,2-2v-1.5c0-0.83-0.67-1.5-1.5-1.5c0.83,0,1.5-0.67,1.5-1.5V9c0-1.1-0.9-2-2-2H3z M21,11v4c0,1.1-0.9,2-2,2h-5c-1.1,0-2-0.9-2-2V9c0-1.1,0.9-2,2-2h5c1.1,0,2,0.9,2,2h-2h-5v6h5v-2h-2.5v-2H21z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
new file mode 100644
index 0000000..8e22e06
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M9,7H7v5H5V7H3v7h4v3h2v-3h2v-2H9V7z M17,11v2h2v2h-5V9h7c0-1.1-0.9-2-2-2h-5c-1.1,0-2,0.9-2,2v6c0,1.1,0.9,2,2,2h5 c1.1,0,2-0.9,2-2v-4H17z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
new file mode 100644
index 0000000..32add0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13,11v2h2v2h-4V9h6c0-1.1-0.9-2-2-2h-4C9.9,7,9,7.9,9,9v6c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4H13z M24,11h-2V9h-2v2h-2v2 h2v2h2v-2h2V11z M7,7H5v5H3V7H1v7h4v3h2v-3h1v-2H7V7z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
new file mode 100644
index 0000000..80e507b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M 16 9 L 16 7 L 8 7 L 8 17 L 16 17 L 16 15 L 10 15 L 10 13 L 16 13 L 16 11 L 10 11 L 10 9 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
new file mode 100644
index 0000000..04049ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,11v2h2v2H9V9h0.44H14h2c0-1.1-0.9-2-2-2H9C7.9,7,7,7.9,7,9v6c0,1.1,0.9,2,2,2h5c1.1,0,2-0.9,2-2v-4H12z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
new file mode 100644
index 0000000..31cc4a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M15,11H9V7H7v10h2v-4h6v4h2V7h-2V11z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
new file mode 100644
index 0000000..ca1020e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
@@ -0,0 +1,32 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,11H6V7H4v10h2v-4h6v4h2V7h-2V11z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M22,11h-2V9h-2v2h-2v2h2v2h2v-2h2V11z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
new file mode 100644
index 0000000..5d90965
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M6,14h3v2H4V8h2V14z M9,10h2v6h2v-6h2V8H9V10z M21,10V8h-5v8h2h3v-2h-3v-0.67V13h3v-2h-3v-1H21z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
new file mode 100644
index 0000000..0366e24
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M3,14h3v2H1V8h2V14z M5,10h2v6h2v-6h2V8H5V10z M12,16h5v-2h-3v-1h3v-2h-3v-1h3V8h-5V16z M24,11h-2V9h-2v2h-2v2h2v2h2v-2h2 V11z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
deleted file mode 100644
index b78d3bf..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="32.0dp"
-        android:height="32.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
-        android:fillAlpha="0.3"
-        android:fillColor="#FFFFFF"/>
-    <path
-        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
-        android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
deleted file mode 100644
index 5217748..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="12.0dp"
-        android:height="24dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
deleted file mode 100644
index 546a96f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="15dp"
-        android:height="24dp"
-        android:viewportWidth="15.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
deleted file mode 100644
index 26b68c7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="12.0dp"
-        android:height="24dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
deleted file mode 100644
index 6e4b4c5..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="15.0dp"
-        android:height="20.0dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
deleted file mode 100644
index c841a66..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.799999,22.299999l-1.199999,-1.299999 0.000000,0.000000 -9.600000,-10.000000 0.000000,0.000000 -6.400000,-6.700000 -1.300000,1.300000 6.400000,6.700000 -8.700000,8.700000 16.900000,0.000000 2.600000,2.700001z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,1.000000l-8.600000,8.600000 8.600000,9.100000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
deleted file mode 100644
index f4b6ed8..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="12dp"
-        android:height="24dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-  <group
-    android:translateX="3.5" >
-    <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
-  </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
deleted file mode 100644
index 60a7f1e9..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="12dp"
-        android:height="24dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <group android:translateX="3.5" >
-      <path
-          android:fillColor="#FFFFFFFF"
-          android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
deleted file mode 100644
index 4ffb4be..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="12dp"
-        android:height="24dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-      <group
-        android:translateX="3.5" >
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
-      </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
deleted file mode 100644
index 816cd32..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="11.9dp"
-        android:height="22dp"
-        android:viewportWidth="13.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.300000,3.800000L7.000000,3.800000L7.000000,11.000000L5.300000,11.000000L5.300000,3.800000L4.000000,3.800000L4.000000,2.500000l4.300000,0.000000L8.300000,3.800000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.400000,7.300000l-1.700000,0.000000l0.000000,2.400000l2.100000,0.000000L12.799999,11.000000L9.000000,11.000000L9.000000,2.500000l3.700000,0.000000l0.000000,1.300000l-2.100000,0.000000l0.000000,2.100000l1.700000,0.000000L12.300000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
deleted file mode 100644
index 4c43e13..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="15.0dp"
-        android:height="19.5dp"
-        android:viewportWidth="18.5"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml b/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
deleted file mode 100644
index c8c857c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,22.000000l20.000000,0.000000L22.000000,2.000000L2.000000,22.000000zM20.000000,20.000000L6.800000,20.000000L20.000000,6.800000L20.000000,20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_swap_vert.xml b/packages/SystemUI/res/drawable/ic_swap_vert.xml
new file mode 100644
index 0000000..eed79ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_swap_vert.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z" />
+</vector>
\ No newline at end of file
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/drawable/stat_sys_data_fully_connected_1x.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
deleted file mode 100644
index d7463a4..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8.5dp"
-        android:height="17dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
deleted file mode 100644
index 6309b6d..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="9.208dp"
-        android:height="17dp"
-        android:viewportWidth="13.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
deleted file mode 100644
index 4067ae5..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8.5dp"
-        android:height="17dp"
-        android:viewportWidth="12.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
deleted file mode 100644
index 719a6ca..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="10.5dp"
-        android:height="14.0dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
deleted file mode 100644
index acaa9b1..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="3.541dp"
-        android:height="17dp"
-        android:viewportWidth="5.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
deleted file mode 100644
index 7985237..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="4.958dp"
-        android:height="17dp"
-        android:viewportWidth="7.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
deleted file mode 100644
index fda8761..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="4.25dp"
-        android:height="17dp"
-        android:viewportWidth="6.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
deleted file mode 100644
index c08ff20..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="9.208dp"
-        android:height="17dp"
-        android:viewportWidth="13.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.300000,3.800000L7.000000,3.800000L7.000000,11.000000L5.300000,11.000000L5.300000,3.800000L4.000000,3.800000L4.000000,2.500000l4.300000,0.000000L8.300000,3.800000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.400000,7.300000l-1.700000,0.000000l0.000000,2.400000l2.100000,0.000000L12.799999,11.000000L9.000000,11.000000L9.000000,2.500000l3.700000,0.000000l0.000000,1.300000l-2.100000,0.000000l0.000000,2.100000l1.700000,0.000000L12.300000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
deleted file mode 100644
index 62159b3..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="11.08dp"
-        android:height="14.0dp"
-        android:viewportWidth="19.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
-</vector>
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 f02c0ba..1bdaf6e 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -26,115 +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="@color/fingerprint_dialog_bg_color">
+        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="center"
-            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="12dp"
-            android:layout_marginStart="24dp"
-            android:layout_marginEnd="24dp"
-            android:gravity="center_horizontal"
-            android:textSize="14sp"
-            android:maxLines="1"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:marqueeRepeatLimit="marquee_forever"
-            android:textColor="@color/fingerprint_dialog_text_light_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:paddingTop="24dp"
-            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="32dp"
-            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="16dp"
-            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/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index b8ed09e..2e92042 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -16,17 +16,18 @@
 ** limitations under the License.
 */
 -->
-<LinearLayout
+<com.android.keyguard.AlphaOptimizedLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/mobile_combo"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    >
+    android:layout_gravity="center_vertical"
+    android:orientation="horizontal">
     <FrameLayout
         android:layout_height="17dp"
-        android:layout_width="wrap_content">
+        android:layout_width="wrap_content"
+        android:layout_gravity="center_vertical">
         <ImageView
             android:id="@+id/mobile_in"
             android:layout_height="wrap_content"
@@ -44,9 +45,16 @@
             android:visibility="gone"
             />
     </FrameLayout>
+    <ImageView
+        android:id="@+id/mobile_type"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:visibility="gone" />
     <FrameLayout
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical">
         <com.android.systemui.statusbar.AnimatedImageView
             android:theme="@style/DualToneLightTheme"
             android:id="@+id/mobile_signal"
@@ -63,11 +71,6 @@
             systemui:hasOverlappingRendering="false"
             />
         <ImageView
-            android:id="@+id/mobile_type"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-        <ImageView
             android:id="@+id/mobile_roaming"
             android:layout_width="wrap_content"
             android:layout_height="17dp"
@@ -79,4 +82,4 @@
             android:contentDescription="@string/data_connection_roaming"
             android:visibility="gone" />
     </FrameLayout>
-</LinearLayout>
+</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 759d1ed..b1cb6cf 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -29,6 +29,7 @@
 
     <!-- Package Info -->
     <RelativeLayout
+        android:id="@+id/header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:clipChildren="false"
@@ -140,6 +141,12 @@
                 android:layout_height="match_parent"
                 style="@style/TextAppearance.NotificationInfo.Button"/>
             <TextView
+                android:id="@+id/minimize"
+                android:text="@string/inline_minimize_button"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                style="@style/TextAppearance.NotificationInfo.Button" />
+            <TextView
                 android:id="@+id/keep"
                 android:text="@string/inline_keep_button"
                 android:layout_width="wrap_content"
@@ -157,10 +164,11 @@
         android:visibility="gone"
         android:orientation="horizontal" >
         <TextView
+            android:id="@+id/confirmation_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/notification_channel_disabled"
-            style="@style/TextAppearance.NotificationInfo.Secondary.Warning"/>
+            style="@style/TextAppearance.NotificationInfo.Confirmation"/>
         <TextView
             android:id="@+id/undo"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 9bf7870..7500bc6 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -43,6 +43,14 @@
         android:layout_gravity="center_vertical"
         android:gravity="end" >
 
+        <include
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical|start"
+            android:layout_margin="15dp"
+            android:visibility="gone"
+            layout="@layout/mobile_signal_group" />
+
         <com.android.keyguard.CarrierText
             android:id="@+id/qs_carrier_text"
             android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index b6d241b..0a3f4eb 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.systemui.volume.VolumeUiLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
@@ -73,20 +73,22 @@
                     <!-- 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>
 
     </LinearLayout>
-</com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
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-h650dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
similarity index 75%
copy from packages/SystemUI/res/values-h650dp/dimens.xml
copy to packages/SystemUI/res/values-h800dp/dimens.xml
index 8a00953..6a0e880 100644
--- a/packages/SystemUI/res/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -1,5 +1,5 @@
 <!--
-  ~ Copyright (C) 2014 The Android Open Source Project
+  ~ 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.
@@ -15,5 +15,6 @@
   -->
 
 <resources>
-    <dimen name="keyguard_clock_notifications_margin">32dp</dimen>
+    <!-- Minimum margin between clock and top of screen or ambient indication -->
+    <dimen name="keyguard_clock_top_margin">76dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e2a94df..5b038b1 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -160,12 +160,12 @@
     <color name="smart_reply_button_background">#fff2f2f2</color>
 
     <!-- Fingerprint dialog colors -->
-    <color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
-    <color name="fingerprint_dialog_text_dark_color">#ff212121</color>
-    <color name="fingerprint_dialog_text_light_color">#ff757575</color>
+    <color name="fingerprint_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
+    <color name="fingerprint_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
+    <color name="fingerprint_dialog_text_light_color">#89000000</color> <!-- 54% black -->
     <color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
-    <color name="fingerprint_dialog_error_message_color">#ffff5722</color>
-    <color name="fingerprint_dialog_fingerprint_color">#ff009688</color>
+    <color name="fingerprint_dialog_error_message_color">#ffd93025</color> <!-- google red 600 -->
+    <color name="fingerprint_dialog_fingerprint_color">#ff008577</color> <!-- google blue 600 -->
 
     <!-- Logout button -->
     <color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e12f7b7..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 -->
@@ -443,8 +449,8 @@
 
     <!-- The margin between the clock and the notifications on Keyguard.-->
     <dimen name="keyguard_clock_notifications_margin">30dp</dimen>
-    <!-- Minimum margin between clock and top of screen or ambient indication -->
-    <dimen name="keyguard_clock_top_margin">26dp</dimen>
+    <!-- Minimum margin between clock and status bar -->
+    <dimen name="keyguard_clock_top_margin">36dp</dimen>
     <dimen name="heads_up_scrim_height">250dp</dimen>
 
     <item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
@@ -906,8 +912,9 @@
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
 
     <!-- Fingerprint Dialog values -->
-    <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
+    <dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
     <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
+    <dimen name="fingerprint_dialog_corner_size">2dp</dimen>
 
     <!-- Wireless Charging Animation values -->
     <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
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-h650dp/dimens.xml b/packages/SystemUI/res/values/integers.xml
similarity index 76%
rename from packages/SystemUI/res/values-h650dp/dimens.xml
rename to packages/SystemUI/res/values/integers.xml
index 8a00953..8f23283 100644
--- a/packages/SystemUI/res/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2014 The Android Open Source Project
+  ~ 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.
@@ -13,7 +14,6 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-
 <resources>
-    <dimen name="keyguard_clock_notifications_margin">32dp</dimen>
+    <integer name="fingerprint_dialog_text_gravity">8388611</integer> <!-- gravity start -->
 </resources>
\ No newline at end of file
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 89e6da3..cce38f1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -780,6 +780,9 @@
     <string name="quick_settings_hotspot_label">Hotspot</string>
     <!-- QuickSettings: Hotspot. Secondary label shown when the hotspot is being enabled [CHAR LIMIT=NONE] -->
     <string name="quick_settings_hotspot_secondary_label_transient">Turning on&#8230;</string>
+    <!-- QuickSettings: Hotspot. Secondary label shown when Data Saver mode is enabled to explain to
+         the user why they can't toggle the hotspot tile. [CHAR LIMIT=20] -->
+    <string name="quick_settings_hotspot_secondary_label_data_saver_enabled">Data Saver is on</string>
     <!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] -->
     <plurals name="quick_settings_hotspot_secondary_label_num_devices">
         <item quantity="one">%d device</item>
@@ -1268,6 +1271,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>
 
@@ -1526,6 +1532,9 @@
     <!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
     <string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
 
+    <!-- Notification inline controls: Shown when a channel's notifications are minimized -->
+    <string name="notification_channel_minimized">These notifications will be minimized</string>
+
     <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
     <string name="inline_blocking_helper">You usually dismiss these notifications.
     \nKeep showing them?</string>
@@ -1539,6 +1548,9 @@
     <!-- Notification inline controls: keep getting notifications button -->
     <string name="inline_keep_button">Keep showing</string>
 
+    <!-- Notification inline controls: minimize notifications button -->
+    <string name="inline_minimize_button">Minimize</string>
+
     <!-- Notification Inline controls: continue receiving notifications prompt, app level -->
     <string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d006af1..1470dfa 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -335,6 +335,7 @@
     <style name="qs_theme" parent="qs_base">
         <item name="lightIconTheme">@style/QSIconTheme</item>
         <item name="darkIconTheme">@style/QSIconTheme</item>
+        <item name="android:windowIsFloating">true</item>
     </style>
 
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
@@ -345,7 +346,9 @@
 
     <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
 
-    <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
+    <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
+        <item name="android:windowIsFloating">true</item>
+    </style>
 
     <style name="QSBorderlessButton">
         <item name="android:padding">12dp</item>
@@ -456,6 +459,12 @@
         <item name="android:alpha">0.87</item>
     </style>
 
+    <style name="TextAppearance.NotificationInfo.Confirmation">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:alpha">0.87</item>
+    </style>
+
     <style name="TextAppearance.NotificationInfo.Secondary">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">14sp</item>
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/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
new file mode 100644
index 0000000..0d5933e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -0,0 +1,34 @@
+/*
+ * 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.systemui.shared.system;
+
+import android.content.Context;
+
+import com.android.internal.util.LatencyTracker;
+
+/**
+ * @see LatencyTracker
+ */
+public class LatencyTrackerCompat {
+    public static boolean isEnabled(Context context) {
+        return LatencyTracker.isEnabled(context);
+    }
+
+    public static void logToggleRecents(int duration) {
+        LatencyTracker.logAction(LatencyTracker.ACTION_TOGGLE_RECENTS, duration);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index b8c5049..0f52209 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 
-import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
@@ -39,6 +38,7 @@
     public final int prefixOrderIndex;
     public final Point position;
     public final Rect sourceContainerBounds;
+    public final boolean isNotInRecents;
 
     private final RemoteAnimationTarget mTarget;
 
@@ -52,6 +52,7 @@
         position = app.position;
         sourceContainerBounds = app.sourceContainerBounds;
         prefixOrderIndex = app.prefixOrderIndex;
+        isNotInRecents = app.isNotInRecents;
     }
 
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 45d1aad8..5b0f1c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -39,9 +39,15 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.WirelessUtils;
+
 import android.telephony.TelephonyManager;
 
 public class CarrierText extends TextView {
+    /** Do not show missing sim message. */
+    public static final int FLAG_HIDE_MISSING_SIM = 1 << 0;
+    /** Do not show airplane mode message. */
+    public static final int FLAG_HIDE_AIRPLANE_MODE = 1 << 1;
+
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "CarrierText";
 
@@ -55,6 +61,8 @@
 
     private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
 
+    private int mFlags;
+
     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onRefreshCarrierInfo() {
@@ -85,6 +93,11 @@
             }
         };
     };
+
+    public void setDisplayFlags(int flags) {
+        mFlags = flags;
+    }
+
     /**
      * The status of this lock screen. Primarily used for widgets on LockScreen.
      */
@@ -196,8 +209,7 @@
                 // Grab the first subscripton, because they all should contain the emergency text,
                 // described above.
                 displayText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_missing_sim_message_short),
-                        subs.get(0).getCarrierName());
+                        getMissingSimMessage(), subs.get(0).getCarrierName());
             } else {
                 // We don't have a SubscriptionInfo to get the emergency calls only from.
                 // Grab it from the old sticky broadcast if possible instead. We can use it
@@ -223,8 +235,7 @@
                         text = concatenate(plmn, spn);
                     }
                 }
-                displayText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_missing_sim_message_short), text);
+                displayText =  makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
             }
         }
 
@@ -232,11 +243,21 @@
         // APM (airplane mode) != no carrier state. There are carrier services
         // (e.g. WFC = Wi-Fi calling) which may operate in APM.
         if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
-            displayText = getContext().getString(R.string.airplane_mode);
+            displayText = getAirplaneModeMessage();
         }
         setText(displayText);
     }
 
+    private String getMissingSimMessage() {
+        return (mFlags & FLAG_HIDE_MISSING_SIM) == 0
+                ? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
+    }
+
+    private String getAirplaneModeMessage() {
+        return (mFlags & FLAG_HIDE_AIRPLANE_MODE) == 0
+                ? getContext().getString(R.string.airplane_mode) : "";
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 474fc90..62b5004 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -149,7 +149,6 @@
         mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
         mSecurityContainer.setSecurityCallback(this);
         mSecurityContainer.showPrimarySecurityScreen(false);
-        // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 6b99206..f0952f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -331,6 +331,37 @@
         updateVisibility();
     }
 
+    public static class Row extends LinearLayout {
+
+        public Row(Context context) {
+            super(context);
+        }
+
+        public Row(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public Row(Context context, AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+        }
+
+        public Row(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            int width = MeasureSpec.getSize(widthMeasureSpec);
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                if (child instanceof KeyguardSliceButton) {
+                    ((KeyguardSliceButton) child).setMaxWidth(width / 2);
+                }
+            }
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
     /**
      * Representation of an item that appears under the clock on main keyguard message.
      */
@@ -344,7 +375,6 @@
             setPadding(horizontalPadding / 2, 0, horizontalPadding / 2, 0);
             setCompoundDrawablePadding((int) context.getResources()
                     .getDimension(R.dimen.widget_icon_padding));
-            setMaxWidth(KeyguardSliceView.this.getWidth() / 2);
             setMaxLines(1);
             setEllipsize(TruncateAt.END);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index 526e5fa..e18ac74 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -79,8 +79,8 @@
     @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         Data data = mStrokeMap.get(stroke);
-        return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
-                + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
+        return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance(), type)
+                + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage(), type);
     }
 
     private static class Data {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
index e6c42da..e6e42f2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
@@ -17,10 +17,11 @@
 package com.android.systemui.classifier;
 
 public class AnglesPercentageEvaluator {
-    public static float evaluate(float value) {
+    public static float evaluate(float value, int type) {
+        final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
         float evaluation = 0.0f;
-        if (value < 1.00) evaluation++;
-        if (value < 0.90) evaluation++;
+        if (value < 1.00 && !secureUnlock) evaluation++;
+        if (value < 0.90 && !secureUnlock) evaluation++;
         if (value < 0.70) evaluation++;
         return evaluation;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 99cc1a6..6883dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -17,14 +17,15 @@
 package com.android.systemui.classifier;
 
 public class AnglesVarianceEvaluator {
-    public static float evaluate(float value) {
+    public static float evaluate(float value, int type) {
+        final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
         float evaluation = 0.0f;
         if (value > 0.05) evaluation++;
         if (value > 0.10) evaluation++;
         if (value > 0.20) evaluation++;
-        if (value > 0.40) evaluation++;
-        if (value > 0.80) evaluation++;
-        if (value > 1.50) evaluation++;
+        if (value > 0.40 && !secureUnlock) evaluation++;
+        if (value > 0.80 && !secureUnlock) evaluation++;
+        if (value > 1.50 && !secureUnlock) evaluation++;
         return evaluation;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index cb761a9..909896e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -31,6 +31,7 @@
     public static final int LEFT_AFFORDANCE = 5;
     public static final int RIGHT_AFFORDANCE = 6;
     public static final int GENERIC = 7;
+    public static final int BOUNCER_UNLOCK = 8;
 
     /**
      * Contains all the information about touch events from which the classifier can query
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
index e20b1ca6..5f04222 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -33,6 +33,7 @@
                 }
                 break;
             case Classifier.UNLOCK:
+            case Classifier.BOUNCER_UNLOCK:
                 if (!vertical || yDiff >= 0.0) {
                     return falsingEvaluation;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index ed659e2..913e781 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -356,11 +356,12 @@
         mDataCollector.setQsExpanded(expanded);
     }
 
-    public void onTrackingStarted() {
+    public void onTrackingStarted(boolean secure) {
         if (FalsingLog.ENABLED) {
             FalsingLog.i("onTrackingStarted", "");
         }
-        mHumanInteractionClassifier.setType(Classifier.UNLOCK);
+        mHumanInteractionClassifier.setType(secure ?
+                Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
         mDataCollector.onTrackingStarted();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 1d43b1d..4b15fbc 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -180,8 +180,8 @@
             }
         }
         mReceiver = null;
-        mWindowManager.removeView(mDialogView);
         mDialogShowing = false;
+        mDialogView.startDismiss();
     }
 
     private void handleButtonNegative() {
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index e828b2c..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:
@@ -61,7 +64,7 @@
 
     private final IBinder mWindowToken = new Binder();
     private final Interpolator mLinearOutSlowIn;
-    private final Interpolator mFastOutLinearIn;
+    private final WindowManager mWindowManager;
     private final float mAnimationTranslationOffset;
     private final int mErrorTextColor;
     private final int mTextColor;
@@ -74,11 +77,13 @@
     private final LinearLayout mDialog;
     private int mLastState;
 
+    private final float mDisplayWidth;
+
     public FingerprintDialogView(Context context, Handler handler) {
         super(context);
         mHandler = handler;
         mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
-        mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAnimationTranslationOffset = getResources()
                 .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
         mErrorTextColor = Color.parseColor(
@@ -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,43 @@
         });
     }
 
+    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
+            public void run() {
+                mWindowManager.removeView(FingerprintDialogView.this);
+            }
+        };
+
+        postOnAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mLayout.animate()
+                        .alpha(0f)
+                        .setDuration(ANIMATION_DURATION)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .start();
+                mDialog.animate()
+                        .translationY(mAnimationTranslationOffset)
+                        .setDuration(ANIMATION_DURATION)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .withEndAction(endActionRunnable)
+                        .start();
+            }
+        });
+    }
+
     public void setBundle(Bundle bundle) {
         mBundle = bundle;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 6f43a18..e171b53 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.globalactions;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -1356,11 +1357,17 @@
             // Window initialization
             Window window = getWindow();
             window.requestFeature(Window.FEATURE_NO_TITLE);
-            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+            // Inflate the decor view, so the attributes below are not overwritten by the theme.
+            window.getDecorView();
+            window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            window.setLayout(MATCH_PARENT, MATCH_PARENT);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
             window.addFlags(
                     WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
                     | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 3563437..a1adfa6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -15,12 +15,14 @@
 package com.android.systemui.globalactions;
 
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
 import android.app.Dialog;
 import android.app.KeyguardManager;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Point;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
@@ -80,15 +82,21 @@
                 com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
         // Window initialization
         Window window = d.getWindow();
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+        window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        // Inflate the decor view, so the attributes below are not overwritten by the theme.
+        window.getDecorView();
         window.getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
         window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
+        window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-        window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
-                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         window.addFlags(
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
                         | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6940264..a1b17e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -83,6 +83,7 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 
@@ -2011,8 +2012,9 @@
     }
 
     public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
-            ViewGroup container, FingerprintUnlockController fingerprintUnlockController) {
-        mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
+            ViewGroup container, NotificationPanelView panelView,
+            FingerprintUnlockController fingerprintUnlockController) {
+        mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
                 fingerprintUnlockController, mDismissCallbackRegistry);
         return mStatusBarKeyguardViewManager;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index e9888df..dbf1745 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
@@ -27,6 +28,7 @@
 import android.os.UserManager;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -36,15 +38,18 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.CarrierText;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.Utils;
 import com.android.settingslib.drawable.UserIconDrawable;
+import com.android.settingslib.graph.SignalDrawable;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.R.dimen;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.MultiUserSwitch;
 import com.android.systemui.statusbar.phone.SettingsButton;
@@ -64,7 +69,7 @@
     private UserInfoController mUserInfoController;
     private SettingsButton mSettingsButton;
     protected View mSettingsContainer;
-    private View mCarrierText;
+    private CarrierText mCarrierText;
 
     private boolean mQsDisabled;
     private QSPanel mQsPanel;
@@ -86,9 +91,15 @@
 
     private View mActionsContainer;
     private View mDragHandle;
+    private View mMobileGroup;
+    private ImageView mMobileSignal;
+    private ImageView mMobileRoaming;
+    private final int mColorForeground;
+    private final CellSignalState mInfo = new CellSignalState();
 
     public QSFooterImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mColorForeground = Utils.getColorAttr(context, android.R.attr.colorForeground);
     }
 
     @Override
@@ -104,7 +115,12 @@
         mSettingsContainer = findViewById(R.id.settings_button_container);
         mSettingsButton.setOnClickListener(this);
 
+        mMobileGroup = findViewById(R.id.mobile_combo);
+        mMobileSignal = findViewById(R.id.mobile_signal);
+        mMobileRoaming = findViewById(R.id.mobile_roaming);
         mCarrierText = findViewById(R.id.qs_carrier_text);
+        mCarrierText.setDisplayFlags(
+                CarrierText.FLAG_HIDE_AIRPLANE_MODE | CarrierText.FLAG_HIDE_MISSING_SIM);
 
         mMultiUserSwitch = findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
@@ -165,6 +181,7 @@
         return new TouchAnimator.Builder()
                 .addFloat(mDivider, "alpha", 0, 1)
                 .addFloat(mCarrierText, "alpha", 0, 0, 1)
+                .addFloat(mMobileGroup, "alpha", 0, 1)
                 .addFloat(mActionsContainer, "alpha", 0, 1)
                 .addFloat(mDragHandle, "alpha", 1, 0, 0)
                 .setStartDelay(0.15f)
@@ -338,4 +355,64 @@
         }
         mMultiUserAvatar.setImageDrawable(picture);
     }
+
+    private void handleUpdateState() {
+        mMobileGroup.setVisibility(mInfo.visible ? View.VISIBLE : View.GONE);
+        if (mInfo.visible) {
+            mMobileRoaming.setVisibility(mInfo.roaming ? View.VISIBLE : View.GONE);
+            mMobileRoaming.setImageTintList(ColorStateList.valueOf(mColorForeground));
+            SignalDrawable d = new SignalDrawable(mContext);
+            d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
+            mMobileSignal.setImageDrawable(d);
+            mMobileSignal.setImageLevel(mInfo.mobileSignalIconId);
+
+            StringBuilder contentDescription = new StringBuilder();
+            if (mInfo.contentDescription != null) {
+                contentDescription.append(mInfo.contentDescription).append(", ");
+            }
+            if (mInfo.roaming) {
+                contentDescription
+                        .append(mContext.getString(R.string.data_connection_roaming))
+                        .append(", ");
+            }
+            // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+            if (TextUtils.equals(mInfo.typeContentDescription,
+                    mContext.getString(R.string.data_connection_no_internet))
+                || TextUtils.equals(mInfo.typeContentDescription,
+                    mContext.getString(R.string.cell_data_off))) {
+                contentDescription.append(mInfo.typeContentDescription);
+            }
+            mMobileSignal.setContentDescription(contentDescription);
+        }
+    }
+
+    @Override
+    public void setMobileDataIndicators(NetworkController.IconState statusIcon,
+            NetworkController.IconState qsIcon, int statusType,
+            int qsType, boolean activityIn, boolean activityOut,
+            String typeContentDescription,
+            String description, boolean isWide, int subId, boolean roaming) {
+        mInfo.visible = statusIcon.visible;
+        mInfo.mobileSignalIconId = statusIcon.icon;
+        mInfo.contentDescription = statusIcon.contentDescription;
+        mInfo.typeContentDescription = typeContentDescription;
+        mInfo.roaming = roaming;
+        handleUpdateState();
+    }
+
+    @Override
+    public void setNoSims(boolean hasNoSims, boolean simDetected) {
+        if (hasNoSims) {
+            mInfo.visible = false;
+        }
+        handleUpdateState();
+    }
+
+    private final class CellSignalState {
+        boolean visible;
+        int mobileSignalIconId;
+        public String contentDescription;
+        String typeContentDescription;
+        boolean roaming;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index ec4d1a6..a48dcc6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.ColorInt;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
@@ -31,6 +32,7 @@
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
@@ -60,6 +62,8 @@
  */
 public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
         View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
+    private static final String TAG = "QuickStatusBarHeader";
+    private static final boolean DEBUG = false;
 
     /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
     private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
@@ -128,7 +132,7 @@
 
         Rect tintArea = new Rect(0, 0, 0, 0);
         int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
-        float intensity = colorForeground == Color.WHITE ? 0 : 1;
+        float intensity = getColorIntensity(colorForeground);
         int fillColor = fillColorForIntensity(intensity, getContext());
 
         // Set light text on the header icons because they will always be on a black background
@@ -292,6 +296,7 @@
     @Override
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null;
+
         if (mNextAlarmText != null) {
             hideLongPressTooltip(true /* shouldFadeInAlarmText */);
         } else {
@@ -351,6 +356,7 @@
                     .setListener(new AnimatorListenerAdapter() {
                         @Override
                         public void onAnimationEnd(Animator animation) {
+                            if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
                             mLongPressTooltipView.setVisibility(View.INVISIBLE);
 
                             if (shouldShowAlarmText) {
@@ -361,7 +367,6 @@
                     .start();
         } else {
             mLongPressTooltipView.setVisibility(View.INVISIBLE);
-
             if (shouldShowAlarmText) {
                 showAlarmText();
             }
@@ -377,9 +382,11 @@
         mNextAlarmView.setVisibility(View.VISIBLE);
         mNextAlarmTextView.setText(mNextAlarmText);
 
+        // Animate the alarm back in. Make sure to clear the animator listener for the animation!
         mNextAlarmView.animate()
                 .alpha(1f)
                 .setDuration(FADE_ANIMATION_DURATION_MS)
+                .setListener(null)
                 .start();
     }
 
@@ -394,6 +401,8 @@
                     .setListener(new AnimatorListenerAdapter() {
                         @Override
                         public void onAnimationEnd(Animator animation) {
+                            if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
+
                             // Reset the alpha regardless of how the animation ends for the next
                             // time we show this view/want to animate it.
                             mNextAlarmView.setVisibility(View.INVISIBLE);
@@ -443,4 +452,9 @@
                 .getBestDateTimePattern(Locale.getDefault(), skeleton);
         return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
     }
+
+    public static float getColorIntensity(@ColorInt int color) {
+        return color == Color.WHITE ? 0 : 1;
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 66823ca..1cb89c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -92,9 +92,10 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int numTiles = mRecords.size();
         final int width = MeasureSpec.getSize(widthMeasureSpec);
-        final int rows = (numTiles + mColumns - 1) / mColumns;
+        final int numRows = (numTiles + mColumns - 1) / mColumns;
         mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns;
 
+        // Measure each QS tile.
         View previousView = this;
         for (TileRecord record : mRecords) {
             if (record.tileView.getVisibility() == GONE) continue;
@@ -104,9 +105,10 @@
 
         // Only include the top margin in our measurement if we have more than 1 row to show.
         // Otherwise, don't add the extra margin buffer at top.
-        int height = (mCellHeight + mCellMarginVertical) * rows +
-                (rows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
+        int height = (mCellHeight + mCellMarginVertical) * numRows +
+                (numRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
         if (height < 0) height = 0;
+
         setMeasuredDimension(width, height);
     }
 
@@ -122,24 +124,30 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getWidth();
-        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         int row = 0;
         int column = 0;
+
+        // Layout each QS tile.
         for (int i = 0; i < mRecords.size(); i++, column++) {
+            // If we reached the last column available to layout a tile, wrap back to the next row.
             if (column == mColumns) {
+                column = 0;
                 row++;
-                column -= mColumns;
             }
-            TileRecord record = mRecords.get(i);
-            int left = getColumnStart(column);
+
+            final TileRecord record = mRecords.get(i);
             final int top = getRowTop(row);
-            int right;
+            final int right;
+            final int left;
             if (isRtl) {
-                right = w - left;
+                right = w - getColumnStart(column);
                 left = right - mCellWidth;
             } else {
+                left = getColumnStart(column);
                 right = left + mCellWidth;
             }
+
             record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 95504ed..89f86c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -129,6 +129,7 @@
             super.setBatteryLevel(MAX_BATTERY);
             setPowerSave(true);
             setCharging(false);
+            setPowerSaveAsColorError(false);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 57ff1c3..b7a64e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -18,12 +18,9 @@
 
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
@@ -32,6 +29,7 @@
 import android.view.ViewGroup;
 import android.view.WindowManager.LayoutParams;
 import android.widget.Switch;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
@@ -43,7 +41,6 @@
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
 import com.android.systemui.qs.CellTileView;
-import com.android.systemui.qs.CellTileView.SignalIcon;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -159,31 +156,15 @@
         final Resources r = mContext.getResources();
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
-        state.isOverlayIconWide = cb.isDataTypeIconWide;
-        state.overlayIconId = cb.dataTypeIconId;
-
         state.label = r.getString(R.string.mobile_data);
-
-        final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
-                ? cb.signalContentDescription
-                : r.getString(R.string.accessibility_no_signal);
         boolean mobileDataEnabled = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
         state.value = mobileDataEnabled;
-        if (cb.noSim) {
-            state.contentDescription = state.label;
-        } else {
-            state.contentDescription = signalContentDesc + ", " + state.label;
-        }
-
         state.expandedAccessibilityClassName = Switch.class.getName();
-        state.value = mDataController.isMobileDataSupported()
-                && mDataController.isMobileDataEnabled();
-
         if (cb.noSim) {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim);
         } else {
-            state.icon = new SignalIcon(cb.mobileSignalIconId);
+            state.icon = ResourceIcon.get(R.drawable.ic_swap_vert);
         }
 
         if (cb.noSim) {
@@ -199,6 +180,7 @@
             state.state = Tile.STATE_INACTIVE;
             state.secondaryLabel = r.getString(R.string.cell_data_off);
         }
+        state.contentDescription = state.label + ", " + state.secondaryLabel;
     }
 
     private CharSequence getMobileDataDescription(CallbackInfo cb) {
@@ -223,40 +205,18 @@
         return mController.hasMobileDataFeature();
     }
 
-    // Remove the period from the network name
-    public static String removeTrailingPeriod(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if (string.endsWith(".")) {
-            return string.substring(0, length - 1);
-        }
-        return string;
-    }
-
     private static final class CallbackInfo {
         boolean enabled;
-        boolean wifiEnabled;
         boolean airplaneModeEnabled;
-        int mobileSignalIconId;
-        String signalContentDescription;
-        int dataTypeIconId;
         String dataContentDescription;
         boolean activityIn;
         boolean activityOut;
-        String enabledDesc;
         boolean noSim;
-        boolean isDataTypeIconWide;
         boolean roaming;
     }
 
     private final class CellSignalCallback implements SignalCallback {
         private final CallbackInfo mInfo = new CallbackInfo();
-        @Override
-        public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient) {
-            mInfo.wifiEnabled = enabled;
-            refreshState(mInfo);
-        }
 
         @Override
         public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
@@ -267,14 +227,9 @@
                 return;
             }
             mInfo.enabled = qsIcon.visible;
-            mInfo.mobileSignalIconId = qsIcon.icon;
-            mInfo.signalContentDescription = qsIcon.contentDescription;
-            mInfo.dataTypeIconId = qsType;
             mInfo.dataContentDescription = typeContentDescription;
             mInfo.activityIn = activityIn;
             mInfo.activityOut = activityOut;
-            mInfo.enabledDesc = description;
-            mInfo.isDataTypeIconWide = qsType != 0 && isWide;
             mInfo.roaming = roaming;
             refreshState(mInfo);
         }
@@ -282,16 +237,6 @@
         @Override
         public void setNoSims(boolean show, boolean simDetected) {
             mInfo.noSim = show;
-            if (mInfo.noSim) {
-                // Make sure signal gets cleared out when no sims.
-                mInfo.mobileSignalIconId = 0;
-                mInfo.dataTypeIconId = 0;
-                // Show a No SIMs description to avoid emergency calls message.
-                mInfo.enabled = true;
-                mInfo.enabledDesc = mContext.getString(
-                        R.string.keyguard_missing_sim_message_short);
-                mInfo.signalContentDescription = mInfo.enabledDesc;
-            }
             refreshState(mInfo);
         }
 
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/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 81e3d5ad..00d6bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -137,7 +137,6 @@
 
         state.icon = mEnabledStatic;
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
-        state.secondaryLabel = getSecondaryLabel(state.value, isTransient, numConnectedDevices);
         state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         state.isTransient = isTransient;
         state.slash.isSlashed = !state.value && !state.isTransient;
@@ -149,19 +148,26 @@
 
         final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled);
         final boolean isTileActive = (state.value || state.isTransient);
-        state.state = isTileUnavailable
-                ? Tile.STATE_UNAVAILABLE
-                : isTileActive
-                        ? Tile.STATE_ACTIVE
-                        : Tile.STATE_INACTIVE;
+
+        if (isTileUnavailable) {
+            state.state = Tile.STATE_UNAVAILABLE;
+        } else {
+            state.state = isTileActive ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        }
+
+        state.secondaryLabel = getSecondaryLabel(
+                isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices);
     }
 
     @Nullable
-    private String getSecondaryLabel(
-            boolean enabled, boolean isTransient, int numConnectedDevices) {
+    private String getSecondaryLabel(boolean isActive, boolean isTransient,
+            boolean isDataSaverEnabled, int numConnectedDevices) {
         if (isTransient) {
             return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient);
-        } else if (numConnectedDevices > 0 && enabled) {
+        } else if (isDataSaverEnabled) {
+            return mContext.getString(
+                    R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
+        } else if (numConnectedDevices > 0 && isActive) {
             return mContext.getResources().getQuantityString(
                     R.plurals.quick_settings_hotspot_secondary_label_num_devices,
                     numConnectedDevices,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 055e72e..ac26f68 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -26,6 +26,7 @@
 import android.app.ActivityOptions;
 import android.app.trust.TrustManager;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -45,6 +46,8 @@
 
 import android.widget.Toast;
 
+import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
 import com.google.android.collect.Lists;
 
 import com.android.internal.logging.MetricsLogger;
@@ -122,6 +125,11 @@
 
         @Override
         public void onTaskStackChangedBackground() {
+            // Skip background preloading recents in SystemUI if the overview services is bound
+            if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+                return;
+            }
+
             // Check this is for the right user
             if (!checkCurrentUserId(mContext, false /* debug */)) {
                 return;
@@ -257,6 +265,17 @@
         }
     });
 
+    private OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
+            new OverviewProxyService.OverviewProxyListener() {
+        @Override
+        public void onConnectionChanged(boolean isConnected) {
+            if (!isConnected) {
+                // Clear everything when the connection to the overview service
+                Recents.getTaskLoader().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+            }
+        }
+    };
+
     public RecentsImpl(Context context) {
         mContext = context;
         mHandler = new Handler();
@@ -277,6 +296,11 @@
     }
 
     public void onBootCompleted() {
+        // Skip preloading tasks if we are already bound to the service
+        if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+            return;
+        }
+
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index d53cb03..22a186f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,6 +16,13 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Notification;
@@ -445,20 +452,47 @@
         return Ranking.VISIBILITY_NO_OVERRIDE;
     }
 
-    public boolean shouldSuppressScreenOff(String key) {
+    public boolean shouldSuppressFullScreenIntent(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
             return (mTmpRanking.getSuppressedVisualEffects()
-                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0;
+                    & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0;
         }
         return false;
     }
 
-    public boolean shouldSuppressScreenOn(String key) {
+    public boolean shouldSuppressPeek(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
             return (mTmpRanking.getSuppressedVisualEffects()
-                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+                    & SUPPRESSED_EFFECT_PEEK) != 0;
+        }
+        return false;
+    }
+
+    public boolean shouldSuppressStatusBar(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
+        }
+        return false;
+    }
+
+    public boolean shouldSuppressAmbient(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & SUPPRESSED_EFFECT_AMBIENT) != 0;
+        }
+        return false;
+    }
+
+    public boolean shouldSuppressNotificationList(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
         }
         return false;
     }
@@ -576,6 +610,14 @@
             return true;
         }
 
+        if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn.getKey())) {
+            return true;
+        }
+
+        if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn.getKey())) {
+            return true;
+        }
+
         if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS
                 && mGroupManager.isChildInGroupWithSummary(sbn)) {
             return true;
@@ -670,5 +712,9 @@
         public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
         public String getCurrentMediaNotificationKey();
         public NotificationGroupManager getGroupManager();
+        /**
+         * @return true iff the device is dozing
+         */
+        boolean isDozing();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 146de00..48828ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -304,11 +304,7 @@
             return true;
         }
 
-        if (mPowerManager.isInteractive()) {
-            return mNotificationData.shouldSuppressScreenOn(key);
-        } else {
-            return mNotificationData.shouldSuppressScreenOff(key);
-        }
+        return mNotificationData.shouldSuppressFullScreenIntent(key);
     }
 
     private void inflateViews(NotificationData.Entry entry, ViewGroup parent) {
@@ -849,12 +845,13 @@
             return false;
         }
 
-        if (!mPresenter.isDozing() && mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+        if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn.getKey())) {
             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
             return false;
         }
 
-        if (mPresenter.isDozing() && mNotificationData.shouldSuppressScreenOff(sbn.getKey())) {
+        // Peeking triggers an ambient display pulse, so disable peek is ambient is active
+        if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn.getKey())) {
             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index afe906c..b1ad30c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 
 import android.animation.Animator;
@@ -39,6 +40,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -73,6 +75,7 @@
     private boolean mNonblockable;
     private StatusBarNotification mSbn;
     private AnimatorSet mExpandAnimation;
+    private boolean mIsForeground;
 
     private CheckSaveListener mCheckSaveListener;
     private OnSettingsClickListener mOnSettingsClickListener;
@@ -84,7 +87,7 @@
         closeControls(v);
     };
 
-    private OnClickListener mOnStopNotifications = v -> {
+    private OnClickListener mOnStopMinNotifications = v -> {
         swapContent(false);
     };
 
@@ -150,6 +153,8 @@
         mSingleNotificationChannel = notificationChannel;
         mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
         mNegativeUserSentiment = negativeUserSentiment;
+        mIsForeground =
+                (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
 
         int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                 pkg, mAppUid, false /* includeDeleted */);
@@ -290,14 +295,23 @@
 
     private void bindButtons() {
         View block =  findViewById(R.id.block);
-        block.setOnClickListener(mOnStopNotifications);
+        block.setOnClickListener(mOnStopMinNotifications);
         TextView keep = findViewById(R.id.keep);
         keep.setOnClickListener(mOnKeepShowing);
         findViewById(R.id.undo).setOnClickListener(mOnUndo);
+        View minimize = findViewById(R.id.minimize);
+        minimize.setOnClickListener(mOnStopMinNotifications);
 
         if (mNonblockable) {
             keep.setText(R.string.notification_done);
             block.setVisibility(GONE);
+            minimize.setVisibility(GONE);
+        } else if (mIsForeground) {
+            block.setVisibility(GONE);
+            minimize.setVisibility(VISIBLE);
+        } else if (!mIsForeground) {
+            block.setVisibility(VISIBLE);
+            minimize.setVisibility(GONE);
         }
 
         // app settings link
@@ -306,7 +320,7 @@
                 mSbn.getId(), mSbn.getTag());
         if (settingsIntent != null
                 && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
-            settingsLinkView.setVisibility(View.VISIBLE);
+            settingsLinkView.setVisibility(VISIBLE);
             settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
                     mSbn.getNotification().getSettingsText()));
             settingsLinkView.setOnClickListener((View view) -> {
@@ -322,14 +336,21 @@
             mExpandAnimation.cancel();
         }
 
+        View prompt = findViewById(R.id.prompt);
+        ViewGroup confirmation = findViewById(R.id.confirmation);
+        TextView confirmationText = findViewById(R.id.confirmation_text);
+        View header = findViewById(R.id.header);
+
         if (showPrompt) {
             mChosenImportance = mStartingUserImportance;
+        } else if (mIsForeground) {
+            mChosenImportance = IMPORTANCE_MIN;
+            confirmationText.setText(R.string.notification_channel_minimized);
         } else {
             mChosenImportance = IMPORTANCE_NONE;
+            confirmationText.setText(R.string.notification_channel_disabled);
         }
 
-        View prompt = findViewById(R.id.prompt);
-        View confirmation = findViewById(R.id.confirmation);
         ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
                 prompt.getAlpha(), showPrompt ? 1f : 0f);
         promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
@@ -339,6 +360,7 @@
 
         prompt.setVisibility(showPrompt ? VISIBLE : GONE);
         confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+        header.setVisibility(showPrompt ? VISIBLE : GONE);
 
         mExpandAnimation = new AnimatorSet();
         mExpandAnimation.playTogether(promptAnim, confirmAnim);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 5263bb4..21d3d81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -101,11 +101,6 @@
     void updateNotificationViews();
 
     /**
-     * @return true iff the device is dozing
-     */
-    boolean isDozing();
-
-    /**
      * Returns the maximum number of notifications to show while locked.
      *
      * @param recompute whether something has changed that means we should recompute this value
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
new file mode 100644
index 0000000..5c21fd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
@@ -0,0 +1,62 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+public class VibratorHelper {
+
+    private final Vibrator mVibrator;
+    private final Context mContext;
+    private boolean mHapticFeedbackEnabled;
+
+    final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateHapticFeedBackEnabled();
+        }
+    };
+
+    public VibratorHelper(Context context) {
+        mContext = context;
+        mVibrator = context.getSystemService(Vibrator.class);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true,
+                mVibrationObserver);
+        mVibrationObserver.onChange(false /* selfChange */);
+    }
+
+    public void vibrate(final int effectId) {
+        if (mHapticFeedbackEnabled) {
+            AsyncTask.execute(() ->
+                    mVibrator.vibrate(VibrationEffect.get(effectId, false /* fallback */)));
+        }
+    }
+
+    private void updateHapticFeedBackEnabled() {
+        mHapticFeedbackEnabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
+    }
+}
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/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index edfbd3f..1109955 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.MathUtils;
 import android.util.Slog;
 import android.util.StatsLog;
 import android.view.KeyEvent;
@@ -49,7 +50,8 @@
  */
 public class KeyguardBouncer {
 
-    final static private String TAG = "KeyguardBouncer";
+    private static final String TAG = "KeyguardBouncer";
+    static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
 
     protected final Context mContext;
     protected final ViewMediatorCallback mCallback;
@@ -86,13 +88,25 @@
     }
 
     public void show(boolean resetSecuritySelection) {
+        show(resetSecuritySelection, true /* notifyFalsing */);
+    }
+
+    public void show(boolean resetSecuritySelection, boolean notifyFalsing) {
         final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
         if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
             // In split system user mode, we never unlock system user.
             return;
         }
-        mFalsingManager.onBouncerShown();
         ensureView();
+
+        // On the keyguard, we want to show the bouncer when the user drags up, but it's
+        // not correct to end the falsing session. We still need to verify if those touches
+        // are valid.
+        // Later, at the end of the animation, when the bouncer is at the top of the screen,
+        // onFullyShown() will be called and FalsingManager will stop recording touches.
+        if (notifyFalsing) {
+            mFalsingManager.onBouncerShown();
+        }
         if (resetSecuritySelection) {
             // showPrimarySecurityScreen() updates the current security method. This is needed in
             // case we are already showing and the current security method changed.
@@ -126,6 +140,28 @@
         mCallback.onBouncerVisiblityChanged(true /* shown */);
     }
 
+    /**
+     * This method must be called at the end of the bouncer animation when
+     * the translation is performed manually by the user, otherwise FalsingManager
+     * will never be notified and its internal state will be out of sync.
+     */
+    public void onFullyShown() {
+        mFalsingManager.onBouncerShown();
+    }
+
+    /**
+     * This method must be called at the end of the bouncer animation when
+     * the translation is performed manually by the user, otherwise FalsingManager
+     * will never be notified and its internal state will be out of sync.
+     */
+    public void onFullyHidden() {
+        if (!mShowingSoon) {
+            cancelShowRunnable();
+            inflateView();
+            mFalsingManager.onBouncerHidden();
+        }
+    }
+
     private final Runnable mShowRunnable = new Runnable() {
         @Override
         public void run() {
@@ -247,6 +283,18 @@
         mBouncerPromptReason = mCallback.getBouncerPromptReason();
     }
 
+    /**
+     * Current notification panel expansion
+     * @param fraction 0 when notification panel is collapsed and 1 when expanded.
+     * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
+     */
+    public void setExpansion(float fraction) {
+        if (mKeyguardView != null) {
+            mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction));
+            mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
+        }
+    }
+
     protected void ensureView() {
         // Removal of the view might be deferred to reduce unlock latency,
         // in this case we need to force the removal, otherwise we'll
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 0cf26df..1bd5e33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -79,14 +79,9 @@
     private int mMaxShadeBottom;
 
     /**
-     * Margin that we should respect within the available space.
+     * Minimum distance from the status bar.
      */
-    private int mContainerPadding;
-
-    /**
-     * Position where clock should be when the panel is collapsed.
-     */
-    private int mClockYTarget;
+    private int mContainerTopPadding;
 
     /**
      * @see NotificationPanelView#getMaxPanelHeight()
@@ -109,12 +104,22 @@
     private float mDarkAmount;
 
     /**
+     * If keyguard will require a password or just fade away.
+     */
+    private boolean mCurrentlySecure;
+
+    /**
+     * If notification panel view currently has a touch.
+     */
+    private boolean mTracking;
+
+    /**
      * Refreshes the dimension values.
      */
     public void loadDimens(Resources res) {
         mClockNotificationsMargin = res.getDimensionPixelSize(
                 R.dimen.keyguard_clock_notifications_margin);
-        mContainerPadding = res.getDimensionPixelSize(
+        mContainerTopPadding = res.getDimensionPixelSize(
                 R.dimen.keyguard_clock_top_margin);
         mBurnInPreventionOffsetX = res.getDimensionPixelSize(
                 R.dimen.burn_in_prevention_offset_x);
@@ -124,8 +129,8 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
-            float dark) {
-        mMinTopMargin = minTopMargin;
+            float dark, boolean secure, boolean tracking) {
+        mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
         mExpandedHeight = expandedHeight;
@@ -133,13 +138,8 @@
         mHeight = parentHeight;
         mKeyguardStatusHeight = keyguardStatusHeight;
         mDarkAmount = dark;
-
-        // Where the clock should stop when swiping up.
-        // This should be outside of the display when unlocked or
-        // under then status bar when the bouncer will be shown
-        mClockYTarget = -mKeyguardStatusHeight;
-        // TODO: on bouncer animation follow-up CL
-        // mClockYTarget = mMinTopMargin + mContainerPadding;
+        mCurrentlySecure = secure;
+        mTracking = tracking;
     }
 
     public void run(Result result) {
@@ -173,8 +173,8 @@
 
         float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT
                 - mClockNotificationsMargin - mNotificationStackHeight / 2;
-        if (y < mMinTopMargin + mContainerPadding) {
-            y = mMinTopMargin + mContainerPadding;
+        if (y < mMinTopMargin) {
+            y = mMinTopMargin;
         }
 
         // Don't allow the clock base to be under half of the screen
@@ -190,18 +190,32 @@
         // Dark: Align the bottom edge of the clock at about half of the screen:
         final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
         float clockYRegular = getExpandedClockPosition();
+        float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
         final float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
-        final float clockY = MathUtils.lerp(mClockYTarget, clockYRegular, shadeExpansion);
+        final float clockY = MathUtils.lerp(clockYTarget, clockYRegular, shadeExpansion);
 
         return (int) MathUtils.lerp(clockY, clockYDark, mDarkAmount);
     }
 
+    /**
+     * We might want to fade out the clock when the user is swiping up.
+     * One exception is when the bouncer will become visible, in this cause the clock
+     * should always persist.
+     *
+     * @param y Current clock Y.
+     * @return Alpha from 0 to 1.
+     */
     private float getClockAlpha(int y) {
-        float alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
-                / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
-        alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+        float alphaKeyguard;
+        if (mCurrentlySecure) {
+            alphaKeyguard = 1;
+        } else {
+            alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
+                    / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
+            alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+        }
         return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
     }
 
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 04c5f2f..bb929dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -32,14 +31,13 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import com.android.internal.statusbar.StatusBarIcon;
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Dependency;
@@ -47,7 +45,6 @@
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -214,18 +211,26 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
-    private void updateLayoutConsideringCutout() {
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if (updateLayoutConsideringCutout()) {
+            requestLayout();
+        }
+        return super.onApplyWindowInsets(insets);
+    }
+
+    private boolean updateLayoutConsideringCutout() {
         DisplayCutout dc = getRootWindowInsets().getDisplayCutout();
         if (dc == null) {
-            updateLayoutParamsNoCutout();
+            return updateLayoutParamsNoCutout();
         } else {
-            updateLayoutParamsForCutout(dc);
+            return updateLayoutParamsForCutout(dc);
         }
     }
 
-    private void updateLayoutParamsNoCutout() {
+    private boolean updateLayoutParamsNoCutout() {
         if (mLayoutState == LAYOUT_NO_CUTOUT) {
-            return;
+            return false;
         }
         mLayoutState = LAYOUT_NO_CUTOUT;
 
@@ -244,11 +249,12 @@
                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
         llp.setMarginStart(getResources().getDimensionPixelSize(
                 R.dimen.system_icons_super_container_margin_start));
+        return true;
     }
 
-    private void updateLayoutParamsForCutout(DisplayCutout dc) {
+    private boolean updateLayoutParamsForCutout(DisplayCutout dc) {
         if (mLayoutState == LAYOUT_CUTOUT) {
-            return;
+            return false;
         }
         mLayoutState = LAYOUT_CUTOUT;
 
@@ -275,6 +281,7 @@
         LinearLayout.LayoutParams llp =
                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
         llp.setMarginStart(0);
+        return true;
     }
 
     //TODO: Something is setting signal_cluster to MATCH_PARENT. Why?
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 32720de..03efbb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,6 +39,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
+import android.os.VibrationEffect;
 import android.support.annotation.ColorInt;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -68,6 +69,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.NavigationBarCompat;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.DeadZone;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
@@ -149,6 +151,7 @@
     private Divider mDivider;
     private RecentsOnboarding mRecentsOnboarding;
     private NotificationPanelView mPanelView;
+    private final VibratorHelper mVibratorHelper;
 
     private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
 
@@ -244,6 +247,7 @@
 
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+        mVibratorHelper = new VibratorHelper(context);
 
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -312,6 +316,9 @@
                 } else if (mRecentsButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_OVERVIEW;
                 }
+
+                // Vibrate tick whenever down occurs on navigation bar
+                mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
                 break;
         }
         return mGestureHelper.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
index 1452e0c..e5083c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -95,8 +95,12 @@
     }
 
     private View findNearestChild(MotionEvent event) {
-        return mClickableChildren.stream().map(v -> new Pair<>(distance(v, event), v))
-                .min(Comparator.comparingInt(f -> f.first)).get().second;
+        return mClickableChildren
+                .stream()
+                .filter(v -> v.isAttachedToWindow())
+                .map(v -> new Pair<>(distance(v, event), v))
+                .min(Comparator.comparingInt(f -> f.first))
+                .get().second;
     }
 
     private int distance(View v, MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e77b135..e1aed7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -141,7 +141,7 @@
         }
 
         // showAmbient == show in shade but not shelf
-        if (!showAmbient && notificationData.shouldSuppressScreenOn(entry.key)) {
+        if (!showAmbient && notificationData.shouldSuppressStatusBar(entry.key)) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9d2480b..2711d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -238,7 +238,6 @@
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mNoVisibleNotifications = true;
     private ValueAnimator mDarkAnimator;
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private boolean mUserSetupComplete;
     private int mQsNotificationTopPadding;
     private float mExpandOffset;
@@ -265,10 +264,8 @@
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
 
-        mNotificationContainerParent = (NotificationsQuickSettingsContainer)
-                findViewById(R.id.notification_container_parent);
-        mNotificationStackScroller = (NotificationStackScrollLayout)
-                findViewById(R.id.notification_stack_scroller);
+        mNotificationContainerParent = findViewById(R.id.notification_container_parent);
+        mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mNotificationStackScroller.setOverscrollTopChangedListener(this);
         mNotificationStackScroller.setOnEmptySpaceClickListener(this);
@@ -470,7 +467,9 @@
                     getMaxPanelHeight(),
                     totalHeight,
                     mKeyguardStatusView.getHeight(),
-                    mDarkAmount);
+                    mDarkAmount,
+                    mStatusBar.isKeyguardCurrentlySecure(),
+                    mTracking);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1710,7 +1709,16 @@
     }
 
     private void updateKeyguardBottomAreaAlpha() {
-        float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
+        // There are two possible panel expansion behaviors:
+        // • User dragging up to unlock: we want to fade out as quick as possible
+        //   (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
+        // • User tapping on lock screen: bouncer won't be visible but panel expansion will
+        //   change due to "unlock hint animation." In this case, fading out the bottom area
+        //   would also hide the message that says "swipe to unlock," we don't want to do that.
+        float expansionAlpha = MathUtils.map(isUnlockHintRunning()
+                        ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
+                0f, 1f, getExpandedFraction());
+        float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
         mKeyguardBottomArea.setAlpha(alpha);
         mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -1809,7 +1817,7 @@
 
     @Override
     protected void onTrackingStarted() {
-        mFalsingManager.onTrackingStarted();
+        mFalsingManager.onTrackingStarted(mStatusBar.isKeyguardCurrentlySecure());
         super.onTrackingStarted();
         if (mQsFullyExpanded) {
             mQsExpandImmediate = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index cefe972..b448967 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -27,6 +27,7 @@
     public static final boolean DEBUG = false;
     public static final String TAG = PanelBar.class.getSimpleName();
     private static final boolean SPEW = false;
+    private boolean mBouncerShowing;
 
     public static final void LOG(String fmt, Object... args) {
         if (!DEBUG) return;
@@ -65,6 +66,7 @@
     }
 
     public void setBouncerShowing(boolean showing) {
+        mBouncerShowing = showing;
         int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
 
@@ -122,7 +124,7 @@
         boolean fullyOpened = false;
         if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
         PanelView pv = mPanel;
-        pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
+        pv.setVisibility(expanded || mBouncerShowing ? VISIBLE : INVISIBLE);
         // adjust any other panels that may be partially visible
         if (expanded) {
             if (mState == STATE_CLOSED) {
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 9c2a0e5..3de0a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,14 +23,8 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.os.AsyncTask;
-import android.os.Handler;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -50,10 +44,11 @@
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.VibratorHelper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.function.BiConsumer;
 
 public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
@@ -66,9 +61,9 @@
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
     private boolean mVibrateOnOpening;
-    private boolean mVibrationEnabled;
     protected boolean mLaunchingNotification;
     private int mFixedDuration = NO_FIXED_DURATION;
+    private BiConsumer<Float, Boolean> mExpansionListener;
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -110,13 +105,7 @@
     private FlingAnimationUtils mFlingAnimationUtilsClosing;
     private FlingAnimationUtils mFlingAnimationUtilsDismissing;
     private FalsingManager mFalsingManager;
-    private final Vibrator mVibrator;
-    final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            updateHapticFeedBackEnabled();
-        }
-    };
+    private final VibratorHelper mVibratorHelper;
 
     /**
      * Whether an instant expand request is currently pending and we are just waiting for layout.
@@ -218,18 +207,9 @@
         mFalsingManager = FalsingManager.getInstance(context);
         mNotificationsDragEnabled =
                 getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
-        mVibrator = mContext.getSystemService(Vibrator.class);
+        mVibratorHelper = new VibratorHelper(context);
         mVibrateOnOpening = mContext.getResources().getBoolean(
                 R.bool.config_vibrateOnIconAnimation);
-        mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true,
-                mVibrationObserver);
-        mVibrationObserver.onChange(false /* selfChange */);
-    }
-
-    public void updateHapticFeedBackEnabled() {
-        mVibrationEnabled = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
     }
 
     protected void loadDimens() {
@@ -341,7 +321,8 @@
                     cancelPeek();
                     onTrackingStarted();
                 }
-                if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
+                if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
+                        && !mStatusBar.isBouncerShowing()) {
                     startOpening(event);
                 }
                 break;
@@ -421,9 +402,8 @@
         runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
                 false /* collapseWhenFinished */);
         notifyBarPanelExpansionChanged();
-        if (mVibrateOnOpening && mVibrationEnabled) {
-            AsyncTask.execute(() ->
-                    mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)));
+        if (mVibrateOnOpening) {
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
         }
 
         //TODO: keyguard opens QS a different way; log that too?
@@ -506,7 +486,8 @@
             if (mUpdateFlingOnLayout) {
                 mUpdateFlingVelocity = vel;
             }
-        } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+        } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
+                && !mStatusBar.isBouncerShowing()) {
             long timePassed = SystemClock.uptimeMillis() - mDownTime;
             if (timePassed < ViewConfiguration.getLongPressTimeout()) {
                 // Lets show the user that he can actually expand the panel
@@ -515,7 +496,7 @@
                 // We need to collapse the panel since we peeked to the small height.
                 postOnAnimation(mPostCollapseRunnable);
             }
-        } else {
+        } else if (!mStatusBar.isBouncerShowing()) {
             boolean expands = onEmptySpaceClick(mInitialTouchX);
             onTrackingStopped(expands);
         }
@@ -1115,6 +1096,10 @@
         mStatusBar.onUnlockHintStarted();
     }
 
+    public boolean isUnlockHintRunning() {
+        return mHintAnimationRunning;
+    }
+
     /**
      * Phase 1: Move everything upwards.
      */
@@ -1206,6 +1191,13 @@
         mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
                 || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
                 || mTracking || mHeightAnimator != null);
+        if (mExpansionListener != null) {
+            mExpansionListener.accept(mExpandedFraction, mTracking);
+        }
+    }
+
+    public void setExpansionListener(BiConsumer<Float, Boolean> consumer) {
+        mExpansionListener = consumer;
     }
 
     protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
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 0933c99..5076404 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -31,6 +31,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
 
 import android.widget.FrameLayout;
@@ -40,7 +41,8 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.util.leak.RotationUtils;
+
+import java.util.Objects;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -101,7 +103,7 @@
         // Always have Battery meters in the status bar observe the dark/light modes.
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
         if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
-            postUpdateLayoutForCutout();
+            updateLayoutForCutout();
         }
     }
 
@@ -118,10 +120,20 @@
 
         // May trigger cutout space layout-ing
         if (updateOrientationAndCutout(newConfig.orientation)) {
-            postUpdateLayoutForCutout();
+            updateLayoutForCutout();
+            requestLayout();
         }
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if (updateOrientationAndCutout(mLastOrientation)) {
+            updateLayoutForCutout();
+            requestLayout();
+        }
+        return super.onApplyWindowInsets(insets);
+    }
+
     /**
      *
      * @param newOrientation may pass NO_VALUE for no change
@@ -136,12 +148,9 @@
             }
         }
 
-        if (mDisplayCutout == null) {
-            DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
-            if (cutout != null) {
-                changed = true;
-                mDisplayCutout = cutout;
-            }
+        if (!Objects.equals(getRootWindowInsets().getDisplayCutout(), mDisplayCutout)) {
+            changed = true;
+            mDisplayCutout = getRootWindowInsets().getDisplayCutout();
         }
 
         return changed;
@@ -279,17 +288,6 @@
         updateSafeInsets();
     }
 
-    private void postUpdateLayoutForCutout() {
-        Runnable r = new Runnable() {
-            @Override
-            public void run() {
-                updateLayoutForCutout();
-            }
-        };
-        // Let the cutout emulation draw first
-        postDelayed(r, 0);
-    }
-
     private void updateCutoutLocation() {
         // Not all layouts have a cutout (e.g., Car)
         if (mCutoutSpace == null) {
@@ -317,40 +315,13 @@
         // or letterboxing from the right or left sides.
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+        if (mDisplayCutout == null) {
             lp.leftMargin = 0;
             lp.rightMargin = 0;
             return;
         }
 
-        int leftMargin = 0;
-        int rightMargin = 0;
-        switch (RotationUtils.getRotation(getContext())) {
-            /*
-             * Landscape: <-|
-             * Seascape:  |->
-             */
-            case RotationUtils.ROTATION_LANDSCAPE:
-                leftMargin = getDisplayCutoutHeight();
-                break;
-            case RotationUtils.ROTATION_SEASCAPE:
-                rightMargin = getDisplayCutoutHeight();
-                break;
-            default:
-                break;
-        }
-
-        lp.leftMargin = leftMargin;
-        lp.rightMargin = rightMargin;
-    }
-
-    //TODO: Find a better way
-    private int getDisplayCutoutHeight() {
-        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
-            return 0;
-        }
-
-        Rect r = mDisplayCutout.getBoundingRect();
-        return r.bottom - r.top;
+        lp.leftMargin = mDisplayCutout.getSafeInsetLeft();
+        lp.rightMargin = mDisplayCutout.getSafeInsetRight();
     }
 }
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 e59a6b5..f8b4e07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -35,7 +35,6 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
@@ -97,14 +96,6 @@
      * The most common scrim, the one under the keyguard.
      */
     protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
-    /**
-     * We fade out the bottom scrim when the bouncer is visible.
-     */
-    protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
-    /**
-     * Opacity of the scrim behind the bouncer (the one doing actual background protection.)
-     */
-    protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
 
     static final int TAG_KEY_ANIM = R.id.scrim;
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -130,12 +121,12 @@
     protected float mScrimBehindAlpha;
     protected float mScrimBehindAlphaResValue;
     protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
-    protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
 
     // Assuming the shade is expanded during initialization
     private float mExpansionFraction = 1f;
 
     private boolean mDarkenWhileDragging;
+    private boolean mExpansionAffectsAlpha = true;
     protected boolean mAnimateChange;
     private boolean mUpdatePending;
     private boolean mTracking;
@@ -177,6 +168,7 @@
         mScrimVisibleListener = scrimVisibleListener;
         mContext = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
+        mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         mLightBarController = lightBarController;
         mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
@@ -300,10 +292,8 @@
         return mState;
     }
 
-    protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
-            float scrimBehindAlphaUnlocking) {
+    protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
         mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
-        mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
         ScrimState[] states = ScrimState.values();
         for (int i = 0; i < states.length; i++) {
             states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
@@ -392,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();
@@ -404,9 +398,9 @@
             float interpolatedFract = getInterpolatedFraction();
             float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
             if (mDarkenWhileDragging) {
-                mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, alphaBehind,
+                mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
                         interpolatedFract);
-                mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
+                mCurrentInFrontAlpha = 0;
             } else {
                 mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
                         interpolatedFract);
@@ -455,7 +449,8 @@
         if (mNeedsDrawableColorUpdate) {
             mNeedsDrawableColorUpdate = false;
             final GradientColors currentScrimColors;
-            if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
+            if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED
+                    || mState == ScrimState.BOUNCER) {
                 // Always animate color changes if we're seeing the keyguard
                 mScrimInFront.setColors(mLockColors, true /* animated */);
                 mScrimBehind.setColors(mLockColors, true /* animated */);
@@ -922,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/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 053c5a3..58100ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -66,20 +66,31 @@
     },
 
     /**
-     * Showing password challenge.
+     * Showing password challenge on the keyguard.
      */
     BOUNCER(1) {
         @Override
         public void prepare(ScrimState previousState) {
-            mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING;
-            mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED;
+            mCurrentBehindAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
+            mCurrentInFrontAlpha = 0f;
+        }
+    },
+
+    /**
+     * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
+     */
+    BOUNCER_OCCLUDED(2) {
+        @Override
+        public void prepare(ScrimState previousState) {
+            mCurrentBehindAlpha = 0;
+            mCurrentInFrontAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
         }
     },
 
     /**
      * Changing screen brightness from quick settings.
      */
-    BRIGHTNESS_MIRROR(2) {
+    BRIGHTNESS_MIRROR(3) {
         @Override
         public void prepare(ScrimState previousState) {
             mCurrentBehindAlpha = 0;
@@ -90,7 +101,7 @@
     /**
      * Always on display or screen off.
      */
-    AOD(3) {
+    AOD(4) {
         @Override
         public void prepare(ScrimState previousState) {
             final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
@@ -110,7 +121,7 @@
     /**
      * When phone wakes up because you received a notification.
      */
-    PULSING(4) {
+    PULSING(5) {
         @Override
         public void prepare(ScrimState previousState) {
             mCurrentInFrontAlpha = 0;
@@ -125,7 +136,7 @@
     /**
      * Unlocked on top of an app (launcher or any other activity.)
      */
-    UNLOCKED(5) {
+    UNLOCKED(6) {
         @Override
         public void prepare(ScrimState previousState) {
             mCurrentBehindAlpha = 0;
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 d3fbe27..5c77524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1296,7 +1296,7 @@
                 mDozeScrimController, keyguardViewMediator,
                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
-                getBouncerContainer(), mFingerprintUnlockController);
+                getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
         mKeyguardIndicationController
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -3688,6 +3688,7 @@
     public void finishKeyguardFadingAway() {
         mKeyguardFadingAway = false;
         mKeyguardMonitor.notifyKeyguardDoneFading();
+        mScrimController.setExpansionAffectsAlpha(true);
     }
 
     // TODO: Move this to NotificationLockscreenUserManager.
@@ -4603,6 +4604,7 @@
         if (mAmbientIndicationContainer instanceof DozeReceiver) {
             ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
         }
+        mEntryManager.updateNotifications();
         updateDozingState();
         updateReportRejectedTouchVisibility();
         Trace.endSection();
@@ -4617,8 +4619,13 @@
         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) {
-            mScrimController.transitionTo(ScrimState.BOUNCER);
+            mScrimController.transitionTo(
+                    mIsOccluded ? ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER);
         } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index a009d80..8d536d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,10 +31,10 @@
 import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dependency;
@@ -75,6 +75,7 @@
     protected LockPatternUtils mLockPatternUtils;
     protected ViewMediatorCallback mViewMediatorCallback;
     protected StatusBar mStatusBar;
+    private NotificationPanelView mNotificationPanelView;
     private FingerprintUnlockController mFingerprintUnlockController;
 
     private ViewGroup mContainer;
@@ -88,6 +89,7 @@
     protected boolean mFirstUpdate = true;
     protected boolean mLastShowing;
     protected boolean mLastOccluded;
+    private boolean mLastTracking;
     private boolean mLastBouncerShowing;
     private boolean mLastBouncerDismissible;
     protected boolean mLastRemoteInputActive;
@@ -124,6 +126,7 @@
 
     public void registerStatusBar(StatusBar statusBar,
             ViewGroup container,
+            NotificationPanelView notificationPanelView,
             FingerprintUnlockController fingerprintUnlockController,
             DismissCallbackRegistry dismissCallbackRegistry) {
         mStatusBar = statusBar;
@@ -131,6 +134,32 @@
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
+        mNotificationPanelView = notificationPanelView;
+        notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
+    }
+
+    private void onPanelExpansionChanged(float expansion, boolean tracking) {
+        // We don't want to translate the bounce when the keyguard is occluded, because we're in
+        // a FLAG_SHOW_WHEN_LOCKED activity and need to conserve the original animation.
+        // We also don't want to show the bouncer when the user quickly taps on the display.
+        final boolean noLongerTracking = mLastTracking != tracking && !tracking;
+        if (mOccluded || mNotificationPanelView.isUnlockHintRunning()) {
+            mBouncer.setExpansion(0);
+        } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
+            mBouncer.setExpansion(expansion);
+            if (expansion == 1) {
+                mBouncer.onFullyHidden();
+                updateStates();
+            } else if (!mBouncer.isShowing()) {
+                mBouncer.show(true /* resetSecuritySelection */, false /* notifyFalsing */);
+            } else if (noLongerTracking) {
+                // Notify that falsing manager should stop its session when user stops touching,
+                // even before the animation ends, to guarantee that we're not recording sensitive
+                // data.
+                mBouncer.onFullyShown();
+            }
+        }
+        mLastTracking = tracking;
     }
 
     /**
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 aec05cd..81641da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -27,12 +27,9 @@
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
-import android.os.Vibrator;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
@@ -53,6 +50,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.VibratorHelper;
 
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -75,7 +73,7 @@
     private OnClickListener mOnClickListener;
     private final KeyButtonRipple mRipple;
     private final OverviewProxyService mOverviewProxyService;
-    private final Vibrator mVibrator;
+    private final VibratorHelper mVibratorHelper;
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private final Runnable mCheckLongPress = new Runnable() {
@@ -128,7 +126,7 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         mRipple = new KeyButtonRipple(context, this);
-        mVibrator = mContext.getSystemService(Vibrator.class);
+        mVibratorHelper = new VibratorHelper(context);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         setBackground(mRipple);
     }
@@ -216,6 +214,9 @@
             mGestureAborted = false;
         }
         if (mGestureAborted) {
+            if (mIsPressed) {
+                setPressed(false);
+            }
             return false;
         }
 
@@ -263,14 +264,17 @@
                 break;
             case MotionEvent.ACTION_UP:
                 final boolean doIt = mIsPressed && !mLongClicked;
+                final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
                 if (isProxyConnected) {
                     if (doIt) {
                         // Animate the ripple in on touch up with setPressed and then out later
                         setPressed(true);
-                        performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+                        if (doHapticFeedback) {
+                            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+                        }
                         playSoundEffect(SoundEffectConstants.CLICK);
                     }
-                } else if ((SystemClock.uptimeMillis() - mDownTime) > 150 && !mLongClicked) {
+                } else if (doHapticFeedback && !mLongClicked) {
                     // Always send a release ourselves because it doesn't seem to be sent elsewhere
                     // and it feels weird to sometimes get a release haptic and other times not.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
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 aa24402..487d1c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -579,14 +579,13 @@
 
         public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
                 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
-                int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
-                int qsDataType) {
+                int discContentDesc, int dataContentDesc, int dataType, boolean isWide) {
             super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
                     qsDiscState, discContentDesc);
             mDataContentDescription = dataContentDesc;
             mDataType = dataType;
             mIsWide = isWide;
-            mQsDataType = qsDataType;
+            mQsDataType = dataType; // TODO: remove this field
         }
     }
 
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 d610400..986abef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -21,28 +21,19 @@
 
 class TelephonyIcons {
     //***** Data connection icons
-
-    static final int QS_DATA_G = R.drawable.ic_qs_signal_g;
-    static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g;
-    static final int QS_DATA_E = R.drawable.ic_qs_signal_e;
-    static final int QS_DATA_H = R.drawable.ic_qs_signal_h;
-    static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x;
-    static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
-    static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
-    static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte;
-    static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus;
-
     static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
 
-    static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
-    static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus;
-    static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
-    static final int ICON_E = R.drawable.stat_sys_data_fully_connected_e;
-    static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
-    static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;
-    static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
-    static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus;
-    static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
+    static final int ICON_LTE = R.drawable.ic_lte_mobiledata;
+    static final int ICON_LTE_PLUS = R.drawable.ic_lte_plus_mobiledata;
+    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;
+    static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
+    static final int ICON_1X = R.drawable.ic_1x_mobiledata;
 
     static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
             "CARRIER_NETWORK_CHANGE",
@@ -55,9 +46,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.carrier_network_change_mode,
             0,
-            false,
-            0
-            );
+            false);
 
     static final MobileIconGroup THREE_G = new MobileIconGroup(
             "3G",
@@ -70,9 +59,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_3g,
             TelephonyIcons.ICON_3G,
-            true,
-            TelephonyIcons.QS_DATA_3G
-            );
+            true);
 
     static final MobileIconGroup WFC = new MobileIconGroup(
             "WFC",
@@ -83,8 +70,7 @@
             0,
             0,
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
-            0, 0, false, 0
-            );
+            0, 0, false);
 
     static final MobileIconGroup UNKNOWN = new MobileIconGroup(
             "Unknown",
@@ -95,8 +81,7 @@
             0,
             0,
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
-            0, 0, false, 0
-            );
+            0, 0, false);
 
     static final MobileIconGroup E = new MobileIconGroup(
             "E",
@@ -109,9 +94,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_edge,
             TelephonyIcons.ICON_E,
-            false,
-            TelephonyIcons.QS_DATA_E
-            );
+            false);
 
     static final MobileIconGroup ONE_X = new MobileIconGroup(
             "1X",
@@ -124,9 +107,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_cdma,
             TelephonyIcons.ICON_1X,
-            true,
-            TelephonyIcons.QS_DATA_1X
-            );
+            true);
 
     static final MobileIconGroup G = new MobileIconGroup(
             "G",
@@ -139,9 +120,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_gprs,
             TelephonyIcons.ICON_G,
-            false,
-            TelephonyIcons.QS_DATA_G
-            );
+            false);
 
     static final MobileIconGroup H = new MobileIconGroup(
             "H",
@@ -154,9 +133,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_3_5g,
             TelephonyIcons.ICON_H,
-            false,
-            TelephonyIcons.QS_DATA_H
-            );
+            false);
 
     static final MobileIconGroup FOUR_G = new MobileIconGroup(
             "4G",
@@ -169,9 +146,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g,
             TelephonyIcons.ICON_4G,
-            true,
-            TelephonyIcons.QS_DATA_4G
-            );
+            true);
 
     static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
             "4G+",
@@ -184,9 +159,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g_plus,
             TelephonyIcons.ICON_4G_PLUS,
-            true,
-            TelephonyIcons.QS_DATA_4G_PLUS
-            );
+            true);
 
     static final MobileIconGroup LTE = new MobileIconGroup(
             "LTE",
@@ -199,9 +172,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_lte,
             TelephonyIcons.ICON_LTE,
-            true,
-            TelephonyIcons.QS_DATA_LTE
-            );
+            true);
 
     static final MobileIconGroup LTE_PLUS = new MobileIconGroup(
             "LTE+",
@@ -214,9 +185,7 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_lte_plus,
             TelephonyIcons.ICON_LTE_PLUS,
-            true,
-            TelephonyIcons.QS_DATA_LTE_PLUS
-            );
+            true);
 
     static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
             "DataDisabled",
@@ -229,8 +198,6 @@
             AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.cell_data_off,
             0,
-            false,
-            0
-            );
+            false);
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 716b58841..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) {
@@ -207,13 +213,12 @@
             rescheduleTimeoutH();
             return true;
         });
-        VolumeUiLayout uiLayout = VolumeUiLayout.get(mDialogView);
-        uiLayout.updateRotation();
 
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         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()) {
@@ -389,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);
@@ -609,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);
     }
 
     /**
@@ -619,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() {
@@ -799,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/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
deleted file mode 100644
index 0a3a2ab..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.volume;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.DisplayCutout;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.util.leak.RotationUtils;
-
-public class VolumeUiLayout extends FrameLayout  {
-
-    private View mChild;
-    private int mRotation = ROTATION_NONE;
-    @Nullable
-    private DisplayCutout mDisplayCutout;
-
-    public VolumeUiLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mDisplayCutout = null;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mChild == null) {
-            if (getChildCount() != 0) {
-                mChild = getChildAt(0);
-                updateRotation();
-            } else {
-                return;
-            }
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        updateRotation();
-    }
-
-    private void setDisplayCutout() {
-        if (mDisplayCutout == null && getRootWindowInsets() != null) {
-            DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
-            if (cutout != null) {
-                mDisplayCutout = cutout;
-            }
-        }
-    }
-
-    public void updateRotation() {
-        setDisplayCutout();
-        if (mChild == null) {
-            if (getChildCount() != 0) {
-                mChild = getChildAt(0);
-            }
-        }
-        int rotation = RotationUtils.getRotation(getContext());
-        if (rotation != mRotation) {
-            updateSafeInsets(rotation);
-            mRotation = rotation;
-        }
-    }
-
-    private void updateSafeInsets(int rotation) {
-        // Depending on our rotation, we may have to work around letterboxing from the right
-        // side from the navigation bar or a cutout.
-
-        MarginLayoutParams lp = (MarginLayoutParams) mChild.getLayoutParams();
-
-        int margin = (int) getResources().getDimension(R.dimen.volume_dialog_base_margin);
-        switch (rotation) {
-            /*
-             * Landscape: <-|. Have to deal with the nav bar
-             * Seascape:  |->. Have to deal with the cutout
-             */
-            case RotationUtils.ROTATION_LANDSCAPE:
-                margin += getNavBarHeight();
-                break;
-            case RotationUtils.ROTATION_SEASCAPE:
-                margin += getDisplayCutoutHeight();
-                break;
-            default:
-                break;
-        }
-
-        lp.rightMargin = margin;
-        mChild.setLayoutParams(lp);
-    }
-
-    private int getNavBarHeight() {
-        return (int) getResources().getDimension(R.dimen.navigation_bar_size);
-    }
-
-    //TODO: Find a better way
-    private int getDisplayCutoutHeight() {
-        if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
-            return 0;
-        }
-
-        Rect r = mDisplayCutout.getBoundingRect();
-        return r.bottom - r.top;
-    }
-
-    @Override
-    public ViewOutlineProvider getOutlineProvider() {
-        return super.getOutlineProvider();
-    }
-
-    public static VolumeUiLayout get(View v) {
-        if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
-        if (v.getParent() instanceof View) {
-            return get((View) v.getParent());
-        }
-        return null;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index b8d9b19..01664b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -18,6 +18,8 @@
 
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
 import static android.view.View.GONE;
@@ -147,6 +149,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
         final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
         assertTrue(textView.getText().toString().contains("App Name"));
+        assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
     }
 
     @Test
@@ -213,6 +216,27 @@
     }
 
     @Test
+    public void testBindNotification_BlockButton() throws Exception {
+       mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final View block = mNotificationInfo.findViewById(R.id.block);
+        final View minimize = mNotificationInfo.findViewById(R.id.minimize);
+        assertEquals(VISIBLE, block.getVisibility());
+        assertEquals(GONE, minimize.getVisibility());
+    }
+
+    @Test
+    public void testBindNotification_MinButton() throws Exception {
+        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+        final View block = mNotificationInfo.findViewById(R.id.block);
+        final View minimize = mNotificationInfo.findViewById(R.id.minimize);
+        assertEquals(GONE, block.getVisibility());
+        assertEquals(VISIBLE, minimize.getVisibility());
+    }
+
+    @Test
     public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -324,6 +348,18 @@
     }
 
     @Test
+    public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin()
+            throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), any());
+    }
+
+    @Test
     public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
             throws Exception {
         int originalImportance = mNotificationChannel.getImportance();
@@ -377,6 +413,39 @@
                 anyString(), eq(TEST_UID), updated.capture());
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
+        assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
+    }
+
+    @Test
+    public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
+                null, Collections.singleton(TEST_PACKAGE_NAME));
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        waitForUndoButton();
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), any());
+    }
+
+    @Test
+    public void testMinChangedCallsUpdateNotificationChannel() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        waitForUndoButton();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        ArgumentCaptor<NotificationChannel> updated =
+                ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), updated.capture());
+        assertTrue((updated.getValue().getUserLockedFields()
+                & USER_LOCKED_IMPORTANCE) != 0);
+        assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
     }
 
     @Test
@@ -416,6 +485,40 @@
     }
 
     @Test
+    public void testMinUndoDoesNotMinNotificationChannel() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.undo).performClick();
+        waitForStopButton();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        ArgumentCaptor<NotificationChannel> updated =
+                ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), updated.capture());
+        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
+        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+    }
+
+    @Test
+    public void testCloseControlsDoesNotUpdateiMinIfSaveIsFalse() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        waitForUndoButton();
+        mNotificationInfo.handleCloseControls(false, false);
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
+    }
+
+    @Test
     public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -557,4 +660,57 @@
     public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
         assertFalse(mNotificationInfo.willBeRemoved());
     }
+
+    @Test
+    public void testUndoText_min() throws Exception {
+        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.minimize).performClick();
+        waitForUndoButton();
+        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
+        assertTrue(confirmationText.getText().toString().contains("minimized"));
+    }
+
+    @Test
+    public void testUndoText_block() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
+        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
+        assertTrue(confirmationText.getText().toString().contains("won't see"));
+    }
+
+    @Test
+    public void testNoHeaderOnConfirmation() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
+        assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility());
+    }
+
+    @Test
+    public void testHeaderOnUndo() throws Exception {
+        mNotificationChannel.setImportance(IMPORTANCE_LOW);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
+        mNotificationInfo.findViewById(R.id.undo).performClick();
+        waitForStopButton();
+        assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index a80b045..36fd499 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
+import android.os.Handler;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -27,12 +28,14 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -40,16 +43,15 @@
 public class AutoTileManagerTest extends SysuiTestCase {
 
     @Mock private QSTileHost mQsTileHost;
+    @Mock private AutoAddTracker mAutoAddTracker;
 
     private AutoTileManager mAutoTileManager;
 
     @Before
     public void setUp() throws Exception {
-        mDependency.injectTestDependency(Dependency.BG_LOOPER,
-                TestableLooper.get(this).getLooper());
-        Prefs.putBoolean(mContext, Prefs.Key.QS_NIGHTDISPLAY_ADDED, false);
-        mQsTileHost = Mockito.mock(QSTileHost.class);
-        mAutoTileManager = new AutoTileManager(mContext, mQsTileHost);
+        MockitoAnnotations.initMocks(this);
+        mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
+                new Handler(TestableLooper.get(this).getLooper()));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
index 500d620..667a508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
@@ -88,6 +88,25 @@
         ev.recycle();
     }
 
+
+    @Test
+    public void testNearestView_DetachedViewsExcluded() {
+        View left = mockViewAt(0, 0, 10, 10);
+        when(left.isAttachedToWindow()).thenReturn(false);
+        View right = mockViewAt(20, 0, 10, 10);
+
+        mNearestTouchFrame.addView(left);
+        mNearestTouchFrame.addView(right);
+        mNearestTouchFrame.onMeasure(0, 0);
+
+        // Would go to left view if attached, but goes to right instead as left should be detached.
+        MotionEvent ev = MotionEvent.obtain(0, 0, 0,
+                12 /* x */, 5 /* y */, 0);
+        mNearestTouchFrame.onTouchEvent(ev);
+        verify(right).onTouchEvent(eq(ev));
+        ev.recycle();
+    }
+
     @Test
     public void testHorizontalSelection_Left() {
         View left = mockViewAt(0, 0, 10, 10);
@@ -161,6 +180,7 @@
             return null;
         }).when(v).getLocationInWindow(any());
         when(v.isClickable()).thenReturn(true);
+        when(v.isAttachedToWindow()).thenReturn(true);
 
         // Stupid final methods.
         v.setLeft(0);
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 3ed2fe1..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
@@ -170,12 +170,22 @@
     }
 
     @Test
-    public void transitionToBouncer() {
+    public void transitionToKeyguardBouncer() {
         mScrimController.transitionTo(ScrimState.BOUNCER);
         mScrimController.finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be visible without tint
-        assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+        assertScrimTint(mScrimBehind, false /* tinted */);
+    }
+
+    @Test
+    public void transitionToBouncer() {
+        mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED);
+        mScrimController.finishAnimationsImmediately();
+        // Front scrim should be transparent
+        // Back scrim should be visible without tint
+        assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
         assertScrimTint(mScrimBehind, false /* tinted */);
     }
 
@@ -196,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/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index ff545f0..14baaeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -346,7 +346,7 @@
     public void testShouldPeek_nonSuppressedGroupSummary() {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+        when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mSystemServicesProxy.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
@@ -367,7 +367,7 @@
     public void testShouldPeek_suppressedGroupSummary() {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+        when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mSystemServicesProxy.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
@@ -385,16 +385,32 @@
     }
 
     @Test
-    public void testShouldPeek_suppressedScreenOn_dozing() {
+    public void testShouldPeek_suppressedPeek() {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
         when(mSystemServicesProxy.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
 
-        mStatusBar.mDozing = true;
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
-        when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
+        when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true);
+
+        Notification n = new Notification.Builder(getContext(), "a").build();
+        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+                UserHandle.of(0), null, 0);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+
+        assertFalse(mEntryManager.shouldPeek(entry, sbn));
+    }
+
+    @Test
+    public void testShouldPeek_noSuppressedPeek() {
+        when(mPowerManager.isScreenOn()).thenReturn(true);
+        when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+        when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+        when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+        when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false);
 
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
@@ -405,63 +421,6 @@
     }
 
     @Test
-    public void testShouldPeek_suppressedScreenOn_noDoze() {
-        when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
-        when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
-        mStatusBar.mDozing = false;
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
-        when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
-
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
-                UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        assertFalse(mEntryManager.shouldPeek(entry, sbn));
-    }
-    @Test
-    public void testShouldPeek_suppressedScreenOff_dozing() {
-        when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
-        when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
-        mStatusBar.mDozing = true;
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
-        when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
-
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
-                UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        assertFalse(mEntryManager.shouldPeek(entry, sbn));
-    }
-
-    @Test
-    public void testShouldPeek_suppressedScreenOff_noDoze() {
-        when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
-        when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
-        mStatusBar.mDozing = false;
-        when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
-        when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
-
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
-                UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        assertTrue(mEntryManager.shouldPeek(entry, sbn));
-    }
-
-
-    @Test
     public void testLogHidden() {
         try {
             mStatusBar.handleVisibleToUserChanged(false);
@@ -574,6 +533,7 @@
     public void testFingerprintNotification_UpdatesScrims() {
         mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class);
         mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
+        mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
         mStatusBar.notifyFpAuthModeChanged();
         verify(mScrimController).transitionTo(any(), any());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index e3558d4..2afb48c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -111,8 +111,8 @@
         boolean out = true;
         String typeDescription = "Test 1";
         String description = "Test 2";
-        int type = R.drawable.stat_sys_data_fully_connected_1x;
-        int qsType = R.drawable.ic_qs_signal_1x;
+        int type = TelephonyIcons.ICON_1X;
+        int qsType = TelephonyIcons.ICON_1X;
         boolean wide = true;
         int subId = 5;
         boolean roaming = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 27cd9a0..714ad1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@
     protected static final int DEFAULT_SIGNAL_STRENGTH = DEFAULT_LEVEL;
     protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL;
     protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G;
-    protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_DATA_3G;
+    protected static final int DEFAULT_QS_ICON = TelephonyIcons.ICON_3G;
 
     protected NetworkControllerImpl mNetworkController;
     protected MobileSignalController mMobileSignalController;
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 cf3620d..8629799 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
@@ -6,7 +6,6 @@
 
 import android.net.NetworkCapabilities;
 import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -15,7 +14,6 @@
 
 import com.android.settingslib.net.DataUsageController;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -28,8 +26,7 @@
     public void test3gDataIcon() {
         setupDefaultSignal();
 
-        verifyDataIndicators(TelephonyIcons.ICON_3G,
-                TelephonyIcons.QS_DATA_3G);
+        verifyDataIndicators(TelephonyIcons.ICON_3G);
     }
 
     @Test
@@ -38,8 +35,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_GSM);
 
-        verifyDataIndicators(TelephonyIcons.ICON_G,
-                TelephonyIcons.QS_DATA_G);
+        verifyDataIndicators(TelephonyIcons.ICON_G);
     }
 
     @Test
@@ -48,8 +44,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_CDMA);
 
-        verifyDataIndicators(TelephonyIcons.ICON_1X,
-                TelephonyIcons.QS_DATA_1X);
+        verifyDataIndicators(TelephonyIcons.ICON_1X);
     }
 
     @Test
@@ -58,8 +53,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_EDGE);
 
-        verifyDataIndicators(TelephonyIcons.ICON_E,
-                TelephonyIcons.QS_DATA_E);
+        verifyDataIndicators(TelephonyIcons.ICON_E);
     }
 
     @Test
@@ -68,8 +62,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
 
-        verifyDataIndicators(TelephonyIcons.ICON_LTE,
-                TelephonyIcons.QS_DATA_LTE);
+        verifyDataIndicators(TelephonyIcons.ICON_LTE);
     }
 
     @Test
@@ -78,8 +71,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_HSPA);
 
-        verifyDataIndicators(TelephonyIcons.ICON_H,
-                TelephonyIcons.QS_DATA_H);
+        verifyDataIndicators(TelephonyIcons.ICON_H);
     }
 
     @Test
@@ -88,7 +80,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_IWLAN);
 
-        verifyDataIndicators(0, 0);
+        verifyDataIndicators(0);
     }
 
     @Test
@@ -106,8 +98,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
 
-        verifyDataIndicators(TelephonyIcons.ICON_4G,
-                TelephonyIcons.QS_DATA_4G);
+        verifyDataIndicators(TelephonyIcons.ICON_4G);
     }
 
     @Test
@@ -150,7 +141,7 @@
         TestableLooper.get(this).processAllMessages();
 
         // Don't show the X until the device is setup.
-        verifyDataIndicators(0, 0);
+        verifyDataIndicators(0);
     }
 
     @Test
@@ -165,8 +156,7 @@
         mConfig.alwaysShowDataRatIcon = true;
         mNetworkController.handleConfigurationChanged();
 
-        verifyDataIndicators(TelephonyIcons.ICON_G,
-                TelephonyIcons.QS_DATA_G);
+        verifyDataIndicators(TelephonyIcons.ICON_G);
     }
 
     @Test
@@ -182,8 +172,7 @@
         // the after work.
         mNetworkController.handleConfigurationChanged();
 
-        verifyDataIndicators(TelephonyIcons.ICON_4G,
-                TelephonyIcons.QS_DATA_4G);
+        verifyDataIndicators(TelephonyIcons.ICON_4G);
     }
 
     @Test
@@ -192,14 +181,12 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
 
-        verifyDataIndicators(TelephonyIcons.ICON_LTE,
-                TelephonyIcons.QS_DATA_LTE);
+        verifyDataIndicators(TelephonyIcons.ICON_LTE);
 
         when(mServiceState.getDataNetworkType())
                 .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
         updateServiceState();
-        verifyDataIndicators(TelephonyIcons.ICON_H,
-                TelephonyIcons.QS_DATA_H);
+        verifyDataIndicators(TelephonyIcons.ICON_H);
     }
 
     @Test
@@ -219,9 +206,9 @@
                 DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out);
     }
 
-    private void verifyDataIndicators(int dataIcon, int qsDataIcon) {
+    private void verifyDataIndicators(int dataIcon) {
         verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon,
-                true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false,
+                true, DEFAULT_QS_SIGNAL_STRENGTH, dataIcon, false,
                 false);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 550f4a7..33aa417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -223,7 +223,7 @@
 
             verifyLastQsMobileDataIndicators(true,
                     testStrength,
-                    TelephonyIcons.QS_DATA_1X, false, false);
+                    TelephonyIcons.ICON_1X, false, false);
         }
     }
 
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 e962c0b..07012d8 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
@@ -5453,6 +5452,53 @@
     // OS: P
     ACTION_OPS_GUTS_SETTINGS = 1346;
 
+    // ACTION: Settings > Battery settings > Battery tip > App restriction tip
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP = 1347;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage tip
+    // OS: P
+    ACTION_HIGH_USAGE_TIP = 1348;
+
+    // ACTION: Settings > Battery settings > Battery tip > Summary tip
+    // OS: P
+    ACTION_SUMMARY_TIP = 1349;
+
+    // ACTION: Settings > Battery settings > Battery tip > Smart battery tip
+    // OS: P
+    ACTION_SMART_BATTERY_TIP = 1350;
+
+    // ACTION: Settings > Battery settings > Battery tip > Early warning tip
+    // OS: P
+    ACTION_EARLY_WARNING_TIP = 1351;
+
+    // ACTION: Settings > Battery settings > Battery tip > Low battery tip
+    // OS: P
+    ACTION_LOW_BATTERY_TIP = 1352;
+
+    // ACTION: Settings > Battery settings > Battery tip > App restriction list shown
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP_LIST = 1353;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage list shown
+    // OS: P
+    ACTION_HIGH_USAGE_TIP_LIST = 1354;
+
+    // OPEN: Settings > Date & time > Select time zone -> Region
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_REGION = 1355;
+
+    // OPEN: Settings > Date & time > Select time zone -> Time Zone
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_TIME_ZONE = 1356;
+
+    // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
+
     // ---- 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/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b0b9586..ecd47e8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3129,6 +3129,11 @@
             boolean activeWindowGone = true;
 
             final int windowCount = windows.size();
+
+            // We'll clear accessibility focus if the window with focus is no longer visible to
+            // accessibility services
+            boolean shouldClearAccessibilityFocus =
+                    mAccessibilityFocusedWindowId != INVALID_WINDOW_ID;
             if (windowCount > 0) {
                 for (int i = 0; i < windowCount; i++) {
                     WindowInfo windowInfo = windows.get(i);
@@ -3166,6 +3171,7 @@
                     }
                     if (window.getId() == mAccessibilityFocusedWindowId) {
                         window.setAccessibilityFocused(true);
+                        shouldClearAccessibilityFocus = false;
                     }
                 }
             }
@@ -3176,6 +3182,10 @@
             for (int i = oldWindowCount - 1; i >= 0; i--) {
                 oldWindowList.remove(i).recycle();
             }
+
+            if (shouldClearAccessibilityFocus) {
+                clearAccessibilityFocus(mAccessibilityFocusedWindowId);
+            }
         }
 
         private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 266b2d7..a5339e0 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -59,9 +59,7 @@
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.LocalLog;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -73,6 +71,7 @@
 import android.view.autofill.IAutoFillManagerClient;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.IResultReceiver;
@@ -88,8 +87,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * Entry point service for autofill management.
@@ -105,6 +104,13 @@
     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
 
     private static final char COMPAT_PACKAGE_DELIMITER = ':';
+    private static final char COMPAT_PACKAGE_URL_IDS_DELIMITER = ',';
+    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;
@@ -326,7 +332,7 @@
         if (service == null) {
             service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
                     mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
-                    mDisabledUsers.get(resolvedUserId));
+                    mAutofillCompatState, mDisabledUsers.get(resolvedUserId));
             mServicesCache.put(userId, service);
             addCompatibilityModeRequestsLocked(service, userId);
         }
@@ -544,23 +550,24 @@
     private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
             , int userId) {
         mAutofillCompatState.reset();
-        final ArrayMap<String, Pair<Long, String>> compatPackages =
+        final ArrayMap<String, Long> compatPackages =
                 service.getCompatibilityPackagesLocked();
         if (compatPackages == null || compatPackages.isEmpty()) {
             return;
         }
-        final Set<String> whiteListedPackages = getWhitelistedCompatModePackages();
+
+        final Map<String, String[]> whiteListedPackages = getWhitelistedCompatModePackages();
         final int compatPackageCount = compatPackages.size();
         for (int i = 0; i < compatPackageCount; i++) {
             final String packageName = compatPackages.keyAt(i);
-            if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) {
+            if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) {
                 Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
                 continue;
             }
-            final Long maxVersionCode = compatPackages.valueAt(i).first;
+            final Long maxVersionCode = compatPackages.valueAt(i);
             if (maxVersionCode != null) {
                 mAutofillCompatState.addCompatibilityModeRequest(packageName,
-                        maxVersionCode, userId);
+                        maxVersionCode, whiteListedPackages.get(packageName), userId);
             }
         }
     }
@@ -571,16 +578,60 @@
                 Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
     }
 
-    private @Nullable Set<String> getWhitelistedCompatModePackages() {
-        final String compatPackagesSetting = getWhitelistedCompatModePackagesFromSettings();
-        if (TextUtils.isEmpty(compatPackagesSetting)) {
+    @Nullable
+    private Map<String, String[]> getWhitelistedCompatModePackages() {
+        return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings());
+    }
+
+    @Nullable
+    @VisibleForTesting
+    static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
+        if (TextUtils.isEmpty(setting)) {
             return null;
         }
-        final Set<String> compatPackages = new ArraySet<>();
+
+        final ArrayMap<String, String[]> compatPackages = new ArrayMap<>();
         final SimpleStringSplitter splitter = new SimpleStringSplitter(COMPAT_PACKAGE_DELIMITER);
-        splitter.setString(compatPackagesSetting);
+        splitter.setString(setting);
         while (splitter.hasNext()) {
-            compatPackages.add(splitter.next());
+            final String packageBlock = splitter.next();
+            final int urlBlockIndex = packageBlock.indexOf(COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN);
+            final String packageName;
+            final List<String> urlBarIds;
+            if (urlBlockIndex == -1) {
+                packageName = packageBlock;
+                urlBarIds = DEFAULT_BUTTONS; // TODO(b/74445943): back to null
+            } else {
+                if (packageBlock.charAt(packageBlock.length() - 1)
+                        != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
+                    Slog.w(TAG, "Ignoring entry '" + packageBlock + "' on '" + setting
+                            + "'because it does not end on '" + COMPAT_PACKAGE_URL_IDS_BLOCK_END +
+                            "'");
+                    continue;
+                }
+                packageName = packageBlock.substring(0, urlBlockIndex);
+                urlBarIds = new ArrayList<>();
+                final String urlBarIdsBlock =
+                        packageBlock.substring(urlBlockIndex + 1, packageBlock.length() - 1);
+                if (sVerbose) {
+                    Slog.v(TAG, "pkg:" + packageName + ": block:" + packageBlock + ": urls:"
+                            + urlBarIds + ": block:" + urlBarIdsBlock + ":");
+                }
+                final SimpleStringSplitter splitter2 =
+                        new SimpleStringSplitter(COMPAT_PACKAGE_URL_IDS_DELIMITER);
+                splitter2.setString(urlBarIdsBlock);
+                while (splitter2.hasNext()) {
+                    final String urlBarId = splitter2.next();
+                    urlBarIds.add(urlBarId);
+                }
+            }
+            if (urlBarIds == null) {
+                compatPackages.put(packageName, null);
+            } else {
+                final String[] urlBarIdsArray = new String[urlBarIds.size()];
+                urlBarIds.toArray(urlBarIdsArray);
+                compatPackages.put(packageName, urlBarIdsArray);
+            }
         }
         return compatPackages;
     }
@@ -598,13 +649,41 @@
             return mAutofillCompatState.isCompatibilityModeRequested(
                     packageName, versionCode, userId);
         }
+
     }
 
-    private static final class AutofillCompatState {
+    /**
+     * Compatibility mode metadata per package.
+     */
+    private static final class PackageCompatState {
+        private final long maxVersionCode;
+        private final String[] urlBarResourceIds;
+
+        PackageCompatState(long maxVersionCode, String[] urlBarResourceIds) {
+            this.maxVersionCode = maxVersionCode;
+            this.urlBarResourceIds = urlBarResourceIds;
+        }
+
+        @Override
+        public String toString() {
+            return "PackageCompatState: [maxVersionCode=" + maxVersionCode
+                    + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]";
+        }
+    }
+
+    /**
+     * Compatibility mode metadata associated with all services.
+     *
+     * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
+     * it cannot hold a lock on the main lock when
+     * {@link AutofillCompatState#isCompatibilityModeRequested(String, long, int)} is called by
+     * external services.
+     */
+    static final class AutofillCompatState {
         private final Object mLock = new Object();
 
         @GuardedBy("mLock")
-        private SparseArray<ArrayMap<String, Long>> mUserSpecs;
+        private SparseArray<ArrayMap<String, PackageCompatState>> mUserSpecs;
 
         boolean isCompatibilityModeRequested(@NonNull String packageName,
                 long versionCode, @UserIdInt int userId) {
@@ -612,30 +691,49 @@
                 if (mUserSpecs == null) {
                     return false;
                 }
-                final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+                final ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
                 if (userSpec == null) {
                     return false;
                 }
-                final Long maxVersionCode = userSpec.get(packageName);
-                if (maxVersionCode == null) {
+                final PackageCompatState metadata = userSpec.get(packageName);
+                if (metadata == null) {
                     return false;
                 }
-                return versionCode <= maxVersionCode;
+                return versionCode <= metadata.maxVersionCode;
+            }
+        }
+
+        @Nullable
+        String[] getUrlBarResourceIds(@NonNull String packageName, @UserIdInt int userId) {
+            synchronized (mLock) {
+                if (mUserSpecs == null) {
+                    return null;
+                }
+                final ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
+                if (userSpec == null) {
+                    return null;
+                }
+                final PackageCompatState metadata = userSpec.get(packageName);
+                if (metadata == null) {
+                    return null;
+                }
+                return metadata.urlBarResourceIds;
             }
         }
 
         void addCompatibilityModeRequest(@NonNull String packageName,
-                long versionCode, @UserIdInt int userId) {
+                long versionCode, @Nullable String[] urlBarResourceIds, @UserIdInt int userId) {
             synchronized (mLock) {
                 if (mUserSpecs == null) {
                     mUserSpecs = new SparseArray<>();
                 }
-                ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+                ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
                 if (userSpec == null) {
                     userSpec = new ArrayMap<>();
                     mUserSpecs.put(userId, userSpec);
                 }
-                userSpec.put(packageName, versionCode);
+                userSpec.put(packageName,
+                        new PackageCompatState(versionCode, urlBarResourceIds));
             }
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8622dbe..54ea3ba 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,7 +64,6 @@
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.LocalLog;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -78,12 +77,12 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
+import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
 
 /**
@@ -164,12 +163,15 @@
     @GuardedBy("mLock")
     private FillEventHistory mEventHistory;
 
+    /** Shared instance, doesn't need to be logged */
+    private final AutofillCompatState mAutofillCompatState;
+
     /** When was {@link PruneTask} last executed? */
     private long mLastPrune = 0;
 
     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
-            boolean disabled) {
+            AutofillCompatState autofillCompatState, boolean disabled) {
         mContext = context;
         mLock = lock;
         mRequestsHistory = requestsHistory;
@@ -178,6 +180,7 @@
         mUserId = userId;
         mUi = ui;
         mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
+        mAutofillCompatState = autofillCompatState;
         updateLocked(disabled);
     }
 
@@ -208,14 +211,9 @@
     }
 
 
-    @GuardedBy("mLock")
     @Nullable
-    String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
-        if (mInfo == null) {
-            Slog.w(TAG,  "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
-            return null;
-        }
-        return mInfo.getUrlBarResourceId(packageName);
+    String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
+        return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
     }
 
     @Nullable
@@ -893,7 +891,7 @@
         pw.print(prefix); pw.print("Field classification enabled: ");
             pw.println(isFieldClassificationEnabledLocked());
         pw.print(prefix); pw.print("Compat pkgs: ");
-        final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
+        final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked();
         if (compatPkgs == null) {
             pw.println("N/A");
         } else {
@@ -1022,7 +1020,7 @@
     }
 
     @GuardedBy("mLock")
-    @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
+    @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() {
         if (mInfo != null) {
             return mInfo.getCompatibilityPackages();
         }
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 232dfdc..5c41f3f 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -30,6 +30,7 @@
 import android.view.autofill.AutofillValue;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.ArrayUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -168,21 +169,24 @@
 
     /**
      * Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+     *
+     * @param structure Assist structure
+     * @param urlBarIds list of ids; only the first id found will be sanitized.
      */
     public static void sanitizeUrlBar(@NonNull AssistStructure structure,
-            @NonNull String urlBarId) {
+            @NonNull String[] urlBarIds) {
         final ViewNode urlBarNode = findViewNode(structure, (node) -> {
-            return urlBarId.equals(node.getIdEntry());
+            return ArrayUtils.contains(urlBarIds, node.getIdEntry());
         });
         if (urlBarNode != null) {
             final String domain = urlBarNode.getText().toString();
             if (domain.isEmpty()) {
-                if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+                if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry());
                 return;
             }
             urlBarNode.setWebDomain(domain);
             if (sDebug) {
-                Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+                Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarNode.getIdEntry() + ", domain="
                         + urlBarNode.getWebDomain());
             }
         }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4abf0f8..26598a2 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -274,11 +274,13 @@
                 }
                 if (mCompatMode) {
                     // Sanitize URL bar, if needed
-                    final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+                    final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode(
                             mComponentName.getPackageName());
-                    if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
-                    if (urlBarId != null) {
-                        Helper.sanitizeUrlBar(structure, urlBarId);
+                    if (sDebug) {
+                        Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
+                    }
+                    if (urlBarIds != null) {
+                        Helper.sanitizeUrlBar(structure, urlBarIds);
                     }
                 }
                 structure.sanitizeForParceling(true);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 369df54..6469091 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3525,7 +3525,10 @@
                         dumpAgents(pw);
                         return;
                     } else if ("transportclients".equals(arg.toLowerCase())) {
-                        mTransportManager.dump(pw);
+                        mTransportManager.dumpTransportClients(pw);
+                        return;
+                    } else if ("transportstats".equals(arg.toLowerCase())) {
+                        mTransportManager.dumpTransportStats(pw);
                         return;
                     }
                 }
@@ -3590,7 +3593,7 @@
                 }
             }
 
-            mTransportManager.dump(pw);
+            mTransportManager.dumpTransportClients(pw);
 
             pw.println("Pending init: " + mPendingInits.size());
             for (String s : mPendingInits) {
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index c87d298..6a1bf17 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -44,6 +44,7 @@
 import com.android.server.backup.transport.TransportConnectionListener;
 import com.android.server.backup.transport.TransportNotAvailableException;
 import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.backup.transport.TransportStats;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -64,6 +65,7 @@
     private final PackageManager mPackageManager;
     private final Set<ComponentName> mTransportWhitelist;
     private final TransportClientManager mTransportClientManager;
+    private final TransportStats mTransportStats;
     private OnTransportRegisteredListener mOnTransportRegisteredListener = (c, n) -> {};
 
     /**
@@ -85,7 +87,12 @@
     private volatile String mCurrentTransportName;
 
     TransportManager(Context context, Set<ComponentName> whitelist, String selectedTransport) {
-        this(context, whitelist, selectedTransport, new TransportClientManager(context));
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mTransportWhitelist = Preconditions.checkNotNull(whitelist);
+        mCurrentTransportName = selectedTransport;
+        mTransportStats = new TransportStats();
+        mTransportClientManager = new TransportClientManager(context, mTransportStats);
     }
 
     @VisibleForTesting
@@ -98,6 +105,7 @@
         mPackageManager = context.getPackageManager();
         mTransportWhitelist = Preconditions.checkNotNull(whitelist);
         mCurrentTransportName = selectedTransport;
+        mTransportStats = new TransportStats();
         mTransportClientManager = transportClientManager;
     }
 
@@ -640,10 +648,14 @@
                 !Thread.holdsLock(mTransportLock), "Can't call transport with transport lock held");
     }
 
-    public void dump(PrintWriter pw) {
+    public void dumpTransportClients(PrintWriter pw) {
         mTransportClientManager.dump(pw);
     }
 
+    public void dumpTransportStats(PrintWriter pw) {
+        mTransportStats.dump(pw);
+    }
+
     private static Predicate<ComponentName> fromPackageFilter(String packageName) {
         return transportComponent -> packageName.equals(transportComponent.getPackageName());
     }
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 1a2ca92..fa881a9 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
@@ -51,6 +52,7 @@
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -78,6 +80,7 @@
     private static final int LOG_BUFFER_SIZE = 5;
 
     private final Context mContext;
+    private final TransportStats mTransportStats;
     private final Intent mBindIntent;
     private final ServiceConnection mConnection;
     private final String mIdentifier;
@@ -104,12 +107,14 @@
 
     TransportClient(
             Context context,
+            TransportStats transportStats,
             Intent bindIntent,
             ComponentName transportComponent,
             String identifier,
             String caller) {
         this(
                 context,
+                transportStats,
                 bindIntent,
                 transportComponent,
                 identifier,
@@ -120,12 +125,14 @@
     @VisibleForTesting
     TransportClient(
             Context context,
+            TransportStats transportStats,
             Intent bindIntent,
             ComponentName transportComponent,
             String identifier,
             String caller,
             Handler listenerHandler) {
         mContext = context;
+        mTransportStats = transportStats;
         mTransportComponent = transportComponent;
         mBindIntent = bindIntent;
         mIdentifier = identifier;
@@ -321,11 +328,16 @@
                 (requestedTransport, transportClient) ->
                         transportFuture.complete(requestedTransport);
 
+        long requestTime = SystemClock.elapsedRealtime();
         log(Priority.DEBUG, caller, "Sync connect: calling async");
         connectAsync(requestListener, caller);
 
         try {
-            return transportFuture.get();
+            transport = transportFuture.get();
+            long time = SystemClock.elapsedRealtime() - requestTime;
+            mTransportStats.registerConnectionTime(mTransportComponent, time);
+            log(Priority.DEBUG, caller, String.format(Locale.US, "Connect took %d ms", time));
+            return transport;
         } catch (InterruptedException | ExecutionException e) {
             String error = e.getClass().getSimpleName();
             log(Priority.ERROR, caller, error + " while waiting for transport: " + e.getMessage());
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 96e7d2f..f4e3928 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -37,12 +37,14 @@
     private static final String TAG = "TransportClientManager";
 
     private final Context mContext;
+    private final TransportStats mTransportStats;
     private final Object mTransportClientsLock = new Object();
     private int mTransportClientsCreated = 0;
     private Map<TransportClient, String> mTransportClientsCallerMap = new WeakHashMap<>();
 
-    public TransportClientManager(Context context) {
+    public TransportClientManager(Context context, TransportStats transportStats) {
         mContext = context;
+        mTransportStats = transportStats;
     }
 
     /**
@@ -88,6 +90,7 @@
             TransportClient transportClient =
                     new TransportClient(
                             mContext,
+                            mTransportStats,
                             bindIntent,
                             transportComponent,
                             Integer.toString(mTransportClientsCreated),
diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java
new file mode 100644
index 0000000..4bef81a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java
@@ -0,0 +1,122 @@
+/*
+ * 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 android.annotation.Nullable;
+import android.content.ComponentName;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+/** Responsible for aggregating {@link TransportClient} relevant times. */
+public class TransportStats {
+    private final Object mStatsLock = new Object();
+    private final Map<ComponentName, Stats> mTransportStats = new HashMap<>();
+
+    void registerConnectionTime(ComponentName transportComponent, long timeMs) {
+        synchronized (mStatsLock) {
+            mTransportStats
+                    .computeIfAbsent(transportComponent, name -> new Stats())
+                    .register(timeMs);
+        }
+    }
+
+    /** Returns {@link Stats} for transport whose host service is {@code transportComponent}. */
+    @Nullable
+    public Stats getStatsForTransport(ComponentName transportComponent) {
+        synchronized (mStatsLock) {
+            Stats stats = mTransportStats.get(transportComponent);
+            if (stats == null) {
+                return null;
+            }
+            return new Stats(stats);
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        synchronized (mStatsLock) {
+            Optional<Stats> aggregatedStats =
+                    mTransportStats.values().stream().reduce(Stats::merge);
+            if (aggregatedStats.isPresent()) {
+                dumpStats(pw, "", aggregatedStats.get());
+            }
+            if (!mTransportStats.isEmpty()) {
+                pw.println("Per transport:");
+                for (ComponentName transportComponent : mTransportStats.keySet()) {
+                    Stats stats = mTransportStats.get(transportComponent);
+                    pw.println("    " + transportComponent.flattenToShortString());
+                    dumpStats(pw, "        ", stats);
+                }
+            }
+        }
+    }
+
+    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));
+    }
+
+    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));
+        }
+
+        public int mN;
+        public double mAverage;
+        public long mMax;
+        public long mMin;
+
+        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;
+        }
+
+        private Stats(int n, double average, long max, long min) {
+            mN = n;
+            mAverage = average;
+            mMax = max;
+            mMin = min;
+        }
+
+        private void register(long sample) {
+            mAverage = (mAverage * mN + sample) / (mN + 1);
+            mN++;
+            mMax = Math.max(mMax, sample);
+            mMin = Math.min(mMin, sample);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index a6b71b7..16be680 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -258,7 +258,7 @@
          */
         private void onRunAnyAppOpsChanged(AppStateTracker sender,
                 int uid, @NonNull String packageName) {
-            updateJobsForUidPackage(uid, packageName);
+            updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid));
 
             if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ false)) {
                 unblockAlarmsForUidPackage(uid, packageName);
@@ -279,9 +279,11 @@
          * This is called when the active/idle state changed for a UID.
          */
         private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
-            updateJobsForUid(uid);
+            final boolean isActive = sender.isUidActive(uid);
 
-            if (sender.isUidActive(uid)) {
+            updateJobsForUid(uid, isActive);
+
+            if (isActive) {
                 unblockAlarmsForUid(uid);
             }
         }
@@ -346,14 +348,14 @@
          * Called when the job restrictions for a UID might have changed, so the job
          * scheduler should re-evaluate all restrictions for all jobs.
          */
-        public void updateJobsForUid(int uid) {
+        public void updateJobsForUid(int uid, boolean isNowActive) {
         }
 
         /**
          * Called when the job restrictions for a UID - package might have changed, so the job
          * scheduler should re-evaluate all restrictions for all jobs.
          */
-        public void updateJobsForUidPackage(int uid, String packageName) {
+        public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) {
         }
 
         /**
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 8265262..d31a605 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -20,6 +20,7 @@
 import android.database.ContentObserver;
 import android.os.BatteryStats;
 
+import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -35,7 +36,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
 import android.hardware.health.V1_0.HealthInfo;
@@ -73,6 +73,8 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 
+import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -117,6 +119,8 @@
     private static final int BATTERY_SCALE = 100;    // battery capacity is a percentage
 
     private static final long HEALTH_HAL_WAIT_MS = 1000;
+    private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000;
+    private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100;
 
     // Used locally for determining when to make a last ditch effort to log
     // discharge stats before the device dies.
@@ -178,7 +182,8 @@
     private HealthServiceWrapper mHealthServiceWrapper;
     private HealthHalCallback mHealthHalCallback;
     private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
-    private HandlerThread mHandlerThread;
+    private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
+    private long mLastBatteryLevelChangedSentMs;
 
     public BatteryService(Context context) {
         super(context);
@@ -198,6 +203,8 @@
         mShutdownBatteryTemperature = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
 
+        mBatteryLevelsEventQueue = new ArrayDeque<>();
+
         // watch for invalid charger messages if the invalid_charger switch exists
         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
             UEventObserver invalidChargerObserver = new UEventObserver() {
@@ -585,7 +592,11 @@
             // We are doing this after sending the above broadcasts, so anything processing
             // them will get the new sequence number at that point.  (See for example how testing
             // of JobScheduler's BatteryController works.)
-            sendIntentLocked();
+            sendBatteryChangedIntentLocked();
+            if (mLastBatteryLevel != mHealthInfo.batteryLevel) {
+                sendBatteryLevelChangedIntentLocked();
+            }
+
 
             // Update the battery LED
             mLed.updateLightsLocked();
@@ -610,7 +621,7 @@
         }
     }
 
-    private void sendIntentLocked() {
+    private void sendBatteryChangedIntentLocked() {
         //  Pack up the values and broadcast them to everyone
         final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -639,12 +650,51 @@
                     + ", info:" + mHealthInfo.toString());
         }
 
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
-            }
-        });
+        mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));
+    }
+
+    private void sendBatteryLevelChangedIntentLocked() {
+        Bundle event = new Bundle();
+        long now = SystemClock.elapsedRealtime();
+        event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence);
+        event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
+        event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
+        event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
+        event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
+        event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
+        event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
+        event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
+        event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
+        event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
+
+        boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
+        mBatteryLevelsEventQueue.add(event);
+        // Make sure queue is bounded and doesn't exceed intent payload limits
+        if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) {
+            mBatteryLevelsEventQueue.removeFirst();
+        }
+
+        if (queueWasEmpty) {
+            // send now if last event was before throttle interval, otherwise delay
+            long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS
+                    ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now;
+            mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay);
+        }
+    }
+
+    private void sendEnqueuedBatteryLevelChangedEvents() {
+        ArrayList<Bundle> events;
+        synchronized (mLock) {
+            events = new ArrayList<>(mBatteryLevelsEventQueue);
+            mBatteryLevelsEventQueue.clear();
+        }
+        final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events);
+
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.BATTERY_STATS);
+        mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
     }
 
     private void logBatteryStatsLocked() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 79297aa..30d31b8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1705,6 +1705,7 @@
                             ni != null ? ni.getState().toString() : "?");
                 } catch (RemoteException e) {
                 }
+                intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
             }
             try {
                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 0502117..45c9a71 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -35,6 +35,8 @@
 # Power save state has changed. See BatterySaverController.java for the details.
 2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
 27390 battery_saving_stats (batterySaver|1|5),(interactive|1|5),(doze|1|5),(delta_duration|2|3),(delta_battery_drain|1|1),(delta_battery_drain_percent|1|6),(total_duration|2|3),(total_battery_drain|1|1),(total_battery_drain_percent|1|6)
+# Note when the user activity timeout has been overriden by ActivityManagerService
+27391 user_activity_timeout_override (override|2|3)
 
 #
 # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 70ca161..5b57c14 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -92,7 +92,6 @@
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
-import android.hardware.input.InputManagerInternal;
 import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
 import android.os.Binder;
@@ -2490,16 +2489,6 @@
         }
     }
 
-    private void notifyInputMethodSubtypeChanged(final int userId,
-            @Nullable final InputMethodInfo inputMethodInfo,
-            @Nullable final InputMethodSubtype subtype) {
-        final InputManagerInternal inputManagerInternal =
-                LocalServices.getService(InputManagerInternal.class);
-        if (inputManagerInternal != null) {
-            inputManagerInternal.onInputMethodSubtypeChanged(userId, inputMethodInfo, subtype);
-        }
-    }
-
     /* package */ void setInputMethodLocked(String id, int subtypeId) {
         InputMethodInfo info = mMethodMap.get(id);
         if (info == null) {
@@ -2534,10 +2523,8 @@
                         mCurMethod.changeInputMethodSubtype(newSubtype);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "Failed to call changeInputMethodSubtype");
-                        return;
                     }
                 }
-                notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info, newSubtype);
             }
             return;
         }
@@ -2563,9 +2550,6 @@
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-
-        notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info,
-                getCurrentInputMethodSubtypeLocked());
     }
 
     @Override
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/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/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 7749bd7..2d7520e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2284,22 +2284,22 @@
             // Protect against recursion.
             mStackSupervisor.inResumeTopActivity = true;
             result = resumeTopActivityInnerLocked(prev, options);
+
+            // When resuming the top activity, it may be necessary to pause the top activity (for
+            // example, returning to the lock screen. We suppress the normal pause logic in
+            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
+            // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
+            // to ensure any necessary pause logic occurs. In the case where the Activity will be
+            // shown regardless of the lock screen, the call to
+            // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
+            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+            if (next == null || !next.canTurnScreenOn()) {
+                checkReadyForSleep();
+            }
         } finally {
             mStackSupervisor.inResumeTopActivity = false;
         }
 
-        // When resuming the top activity, it may be necessary to pause the top activity (for
-        // example, returning to the lock screen. We suppress the normal pause logic in
-        // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
-        // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
-        // any necessary pause logic occurs. In the case where the Activity will be shown regardless
-        // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
-        // is skipped.
-        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
-        if (next == null || !next.canTurnScreenOn()) {
-            checkReadyForSleep();
-        }
-
         return result;
     }
 
@@ -2854,7 +2854,7 @@
                 true /* includingParents */);
     }
 
-    final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
+    void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
             boolean newTask, boolean keepCurTransition, ActivityOptions options) {
         TaskRecord rTask = r.getTask();
         final int taskId = rTask.taskId;
@@ -3422,8 +3422,8 @@
      * @param allowFocusSelf Is the focus allowed to remain on the same stack.
      */
     private boolean adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) {
-        final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(
-                allowFocusSelf ? null : this);
+        final ActivityStack stack =
+                mStackSupervisor.getNextFocusableStackLocked(this, !allowFocusSelf);
         final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
             return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0216439..185897a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -679,7 +679,7 @@
     void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
         if (!focusCandidate.isFocusable()) {
             // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
-            focusCandidate = getNextFocusableStackLocked(focusCandidate);
+            focusCandidate = getNextFocusableStackLocked(focusCandidate, false /* ignoreCurrent */);
         }
 
         if (focusCandidate != mFocusedStack) {
@@ -2429,27 +2429,50 @@
      * Get next focusable stack in the system. This will search across displays and stacks
      * in last-focused order for a focusable and visible stack, different from the target stack.
      *
-     * @param currentFocus The stack that previously had focus and thus needs to be ignored when
-     *                     searching for next candidate.
+     * @param currentFocus The stack that previously had focus.
+     * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next
+     *                     candidate.
      * @return Next focusable {@link ActivityStack}, null if not found.
      */
-    ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+    ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus, boolean ignoreCurrent) {
         mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
 
+        final int currentWindowingMode = currentFocus != null
+                ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+        ActivityStack candidate = null;
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
             // If a display is registered in WM, it must also be available in AM.
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
             for (int j = display.getChildCount() - 1; j >= 0; --j) {
                 final ActivityStack stack = display.getChildAt(j);
-                if (stack != currentFocus && stack.isFocusable()
-                        && stack.shouldBeVisible(null)) {
-                    return stack;
+                if (ignoreCurrent && stack == currentFocus) {
+                    continue;
                 }
+                if (!stack.isFocusable() || !stack.shouldBeVisible(null)) {
+                    continue;
+                }
+
+                if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                        && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+                    // If the currently focused stack is in split-screen secondary we would prefer
+                    // the focus to move to another split-screen secondary stack or fullscreen stack
+                    // over the primary split screen stack to avoid:
+                    // - Moving the focus to the primary split-screen stack when it can't be focused
+                    //   because it will be minimized, but AM doesn't know that yet
+                    // - primary split-screen stack overlapping with a fullscreen stack when a
+                    //   fullscreen stack is higher in z than the next split-screen stack. Assistant
+                    //   stack, I am looking at you...
+                    // We only move the focus to the primary-split screen stack if there isn't a
+                    // better alternative.
+                    candidate = stack;
+                    continue;
+                }
+                return stack;
             }
         }
 
-        return null;
+        return candidate;
     }
 
     /**
@@ -3352,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/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 99f5298..f1b3dfa 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -828,6 +828,25 @@
     }
 
     /**
+     * @return ids of tasks that are presented in Recents UI.
+     */
+    SparseBooleanArray getRecentTaskIds() {
+        final SparseBooleanArray res = new SparseBooleanArray();
+        final int size = mTasks.size();
+        int numVisibleTasks = 0;
+        for (int i = 0; i < size; i++) {
+            final TaskRecord tr = mTasks.get(i);
+            if (isVisibleRecentTask(tr)) {
+                numVisibleTasks++;
+                if (isInVisibleRange(tr, numVisibleTasks)) {
+                    res.put(tr.taskId, true);
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
      * @return the task in the task list with the given {@param id} if one exists.
      */
     TaskRecord getTask(int id) {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 322d66b..9121568 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -16,7 +16,6 @@
 
 package com.android.server.am;
 
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
@@ -139,7 +138,7 @@
             // started
             mWindowManager.cancelRecentsAnimation();
             mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
-                    display.mDisplayId);
+                    display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds());
 
             // If we updated the launch-behind state, update the visibility of the activities after
             // we fetch the visible tasks to be controlled by the animation
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 94a64eb..f577d09 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -39,6 +39,7 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -256,6 +257,7 @@
     private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
     private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
     private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
+    private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
     // end of messages handled under wakelock
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -265,6 +267,8 @@
     // retry delay in case of failure to indicate system ready to AudioFlinger
     private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
 
+    private static final int BT_HEARING_AID_GAIN_MIN = -128;
+
     /** @see AudioSystemThread */
     private AudioSystemThread mAudioSystemThread;
     /** @see AudioHandler */
@@ -573,7 +577,7 @@
             AudioSystem.DEVICE_OUT_HDMI_ARC |
             AudioSystem.DEVICE_OUT_SPDIF |
             AudioSystem.DEVICE_OUT_AUX_LINE;
-    int mFullVolumeDevices = 0;
+    int mFullVolumeDevices = AudioSystem.DEVICE_OUT_HEARING_AID;
 
     private final boolean mMonitorRotation;
 
@@ -590,6 +594,10 @@
 
     private final MediaFocusControl mMediaFocusControl;
 
+    // Reference to BluetoothA2dp to query for volume.
+    private BluetoothHearingAid mHearingAid;
+    // lock always taken synchronized on mConnectedDevices
+    private final Object mHearingAidLock = new Object();
     // Reference to BluetoothA2dp to query for AbsoluteVolume.
     private BluetoothA2dp mA2dp;
     // lock always taken synchronized on mConnectedDevices
@@ -849,6 +857,8 @@
         if (adapter != null) {
             adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                     BluetoothProfile.A2DP);
+            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+                                    BluetoothProfile.HEARING_AID);
         }
 
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1607,6 +1617,20 @@
                 }
             }
 
+            // Check if volume update should be send to Hearing Aid
+            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+                synchronized (mHearingAidLock) {
+                    if (mHearingAid != null) {
+                        //hearing aid expect volume value in range -128dB to 0dB
+                        int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, newIndex/10,
+                                AudioSystem.DEVICE_OUT_HEARING_AID);
+                        if (gainDB < BT_HEARING_AID_GAIN_MIN)
+                            gainDB = BT_HEARING_AID_GAIN_MIN;
+                        mHearingAid.setVolume(gainDB);
+                    }
+                }
+            }
+
             // Check if volume update should be sent to Hdmi system audio.
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
@@ -1852,6 +1876,19 @@
                 }
             }
 
+            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+                synchronized (mHearingAidLock) {
+                    if (mHearingAid != null) {
+                        //hearing aid expect volume value in range -128dB to 0dB
+                        int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10, AudioSystem.DEVICE_OUT_HEARING_AID);
+                        if (gainDB < BT_HEARING_AID_GAIN_MIN)
+                            gainDB = BT_HEARING_AID_GAIN_MIN;
+                        mHearingAid.setVolume(gainDB);
+
+                    }
+                }
+            }
+
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
             }
@@ -1915,7 +1952,16 @@
                 }
                 mUserSelectedVolumeControlStream = false;
             } else {
-                mForceControlStreamClient = new ForceControlStreamClient(cb);
+                if (null == mForceControlStreamClient) {
+                    mForceControlStreamClient = new ForceControlStreamClient(cb);
+                } else {
+                    if (mForceControlStreamClient.getBinder() == cb) {
+                        Log.d(TAG, "forceVolumeControlStream cb:" + cb + " is already linked.");
+                    } else {
+                        mForceControlStreamClient.release();
+                        mForceControlStreamClient = new ForceControlStreamClient(cb);
+                    }
+                }
             }
         }
     }
@@ -1955,6 +2001,10 @@
                 mCb = null;
             }
         }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
     }
 
     private void sendBroadcastToAll(Intent intent) {
@@ -3596,6 +3646,30 @@
                 }
                 break;
 
+            case BluetoothProfile.HEARING_AID:
+                synchronized (mConnectedDevices) {
+                    synchronized (mHearingAidLock) {
+                        mHearingAid = (BluetoothHearingAid) proxy;
+                        deviceList = mHearingAid.getConnectedDevices();
+                        if (deviceList.size() > 0) {
+                            btDevice = deviceList.get(0);
+                            int state = mHearingAid.getConnectionState(btDevice);
+                            int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+                            int delay = checkSendBecomingNoisyIntent(
+                                    AudioSystem.DEVICE_OUT_HEARING_AID, intState,
+                                    AudioSystem.DEVICE_NONE);
+                            queueMsgUnderWakeLock(mAudioHandler,
+                                    MSG_SET_HEARING_AID_CONNECTION_STATE,
+                                    state,
+                                    0 /* arg2 unused */,
+                                    btDevice,
+                                    delay);
+                        }
+                    }
+                }
+
+                break;
+
             default:
                 break;
             }
@@ -3615,6 +3689,10 @@
                 disconnectHeadset();
                 break;
 
+            case BluetoothProfile.HEARING_AID:
+                disconnectHearingAid();
+                break;
+
             default:
                 break;
             }
@@ -3625,6 +3703,7 @@
         disconnectA2dp();
         disconnectA2dpSink();
         disconnectHeadset();
+        disconnectHearingAid();
     }
 
     void disconnectA2dp() {
@@ -3676,6 +3755,29 @@
         }
     }
 
+    void disconnectHearingAid() {
+        synchronized (mConnectedDevices) {
+            synchronized (mHearingAidLock) {
+                ArraySet<String> toRemove = null;
+                // Disconnect ALL DEVICE_OUT_HEARING_AID devices
+                for (int i = 0; i < mConnectedDevices.size(); i++) {
+                    DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+                    if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+                        toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+                        toRemove.add(deviceSpec.mDeviceAddress);
+                    }
+                }
+                if (toRemove != null) {
+                    int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+                            0, AudioSystem.DEVICE_NONE);
+                    for (int i = 0; i < toRemove.size(); i++) {
+                        makeHearingAidDeviceUnavailable(toRemove.valueAt(i) /*, delay*/);
+                    }
+                }
+            }
+        }
+    }
+
     private void onCheckMusicActive(String caller) {
         synchronized (mSafeMediaVolumeState) {
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
@@ -4187,7 +4289,8 @@
             handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
             if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
                     msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
+                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+                    msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
                 mLastDeviceConnectMsgTime = time;
             }
         }
@@ -4290,6 +4393,33 @@
     @Override
     public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
     {
+        Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
+
+        setBluetoothHearingAidDeviceConnectionState(
+                device, state,  false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
+    }
+
+    public int setBluetoothHearingAidDeviceConnectionState(
+            BluetoothDevice device, int state, boolean suppressNoisyIntent,
+            int musicDevice)
+    {
+        int delay;
+        synchronized (mConnectedDevices) {
+            if (!suppressNoisyIntent) {
+                int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+                        intState, musicDevice);
+            } else {
+                delay = 0;
+            }
+            queueMsgUnderWakeLock(mAudioHandler,
+                    MSG_SET_HEARING_AID_CONNECTION_STATE,
+                    state,
+                    0 /* arg2 unused */,
+                    device,
+                    delay);
+        }
+        return delay;
     }
 
     public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
@@ -5231,6 +5361,11 @@
                     mAudioEventWakeLock.release();
                     break;
 
+                case MSG_SET_HEARING_AID_CONNECTION_STATE:
+                    onSetHearingAidConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    mAudioEventWakeLock.release();
+                    break;
+
                 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
                     onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
                     mAudioEventWakeLock.release();
@@ -5423,14 +5558,8 @@
                 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
-        synchronized (mCurAudioRoutes) {
-            // Remove A2DP routes as well
-            if (mCurAudioRoutes.bluetoothName != null) {
-                mCurAudioRoutes.bluetoothName = null;
-                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                        SENDMSG_NOOP, 0, 0, null, 0);
-            }
-        }
+        // Remove A2DP routes as well
+        setCurrentAudioRouteName(null);
     }
 
     // must be called synchronized on mConnectedDevices
@@ -5466,6 +5595,28 @@
     }
 
     // must be called synchronized on mConnectedDevices
+    private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
+                new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
+                                   address));
+        sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
+                AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeHearingAidDeviceUnavailable(String address) {
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
+        // Remove Hearing Aid routes as well
+        setCurrentAudioRouteName(null);
+    }
+
+    // must be called synchronized on mConnectedDevices
     private void cancelA2dpDeviceTimeout() {
         mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
     }
@@ -5506,13 +5657,7 @@
                 } else {
                     makeA2dpDeviceUnavailableNow(address);
                 }
-                synchronized (mCurAudioRoutes) {
-                    if (mCurAudioRoutes.bluetoothName != null) {
-                        mCurAudioRoutes.bluetoothName = null;
-                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                                SENDMSG_NOOP, 0, 0, null, 0);
-                    }
-                }
+                setCurrentAudioRouteName(null);
             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
                     // this could be a reconnection after a transient disconnection
@@ -5528,14 +5673,7 @@
                 }
                 makeA2dpDeviceAvailable(address, btDevice.getName(),
                         "onSetA2dpSinkConnectionState");
-                synchronized (mCurAudioRoutes) {
-                    String name = btDevice.getAliasName();
-                    if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
-                        mCurAudioRoutes.bluetoothName = name;
-                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                                SENDMSG_NOOP, 0, 0, null, 0);
-                    }
-                }
+                setCurrentAudioRouteName(btDevice.getAliasName());
             }
         }
     }
@@ -5566,6 +5704,46 @@
         }
     }
 
+    private void onSetHearingAidConnectionState(BluetoothDevice btDevice, int state)
+    {
+        if (DEBUG_DEVICES) {
+            Log.d(TAG, "onSetHearingAidConnectionState btDevice=" + btDevice+", state=" + state);
+        }
+        if (btDevice == null) {
+            return;
+        }
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+
+        synchronized (mConnectedDevices) {
+            final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
+                                                 btDevice.getAddress());
+            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
+
+            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+                makeHearingAidDeviceUnavailable(address);
+                setCurrentAudioRouteName(null);
+            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+                makeHearingAidDeviceAvailable(address, btDevice.getName(),
+                        "onSetHearingAidConnectionState");
+                setCurrentAudioRouteName(btDevice.getAliasName());
+            }
+        }
+    }
+
+    private void setCurrentAudioRouteName(String name){
+        synchronized (mCurAudioRoutes) {
+            if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+                mCurAudioRoutes.bluetoothName = name;
+                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                        SENDMSG_NOOP, 0, 0, null, 0);
+            }
+        }
+    }
+
     private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
     {
         if (DEBUG_DEVICES) {
@@ -5701,6 +5879,7 @@
 
         if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
                 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
+                mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
                 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
             synchronized (mLastDeviceConnectMsgTime) {
                 long time = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 406231a..954c001 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -101,7 +101,9 @@
         }
 
         TunerSession session = module.openSession(callback);
-        session.setConfiguration(legacyConfig);
+        if (legacyConfig != null) {
+            session.setConfiguration(legacyConfig);
+        }
         return session;
     }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index daec97a..816ba0b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -55,7 +55,7 @@
 
     public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
         try {
-            IBroadcastRadio service = IBroadcastRadio.getService();
+            IBroadcastRadio service = IBroadcastRadio.getService(fqName);
             if (service == null) return null;
 
             Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 8efaa2a..8f3f099 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -90,7 +90,8 @@
         if (ret == AudioSystem.AUDIO_STATUS_OK) {
             mIsAudioConnected = connected;
         } else {
-            Slog.e(TAG, "Failed to notify AudioService about new state: " + connected);
+            Slog.e(TAG, "Failed to notify AudioService about new state: "
+                    + connected + ", response was: " + ret);
         }
     }
 
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/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a951d47..451acf4 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,12 +17,10 @@
 package com.android.server.input;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.LocaleList;
 import android.os.ShellCallback;
 import android.util.Log;
 import android.view.Display;
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.SomeArgs;
@@ -79,8 +77,6 @@
 import android.os.MessageQueue;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -99,8 +95,7 @@
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.ViewConfiguration;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
+import android.widget.Toast;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -137,7 +132,6 @@
     private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
     private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
     private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
-    private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
 
     // Pointer to native input manager service object.
     private final long mPtr;
@@ -174,7 +168,8 @@
     private final ArrayList<InputDevice>
             mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
     private boolean mKeyboardLayoutNotificationShown;
-    private InputMethodSubtypeHandle mCurrentImeHandle;
+    private PendingIntent mKeyboardLayoutIntent;
+    private Toast mSwitchedKeyboardLayoutToast;
 
     // State for vibrator tokens.
     private Object mVibratorLock = new Object();
@@ -1368,82 +1363,6 @@
     }
 
     @Override // Binder call
-    @Nullable
-    public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
-        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
-        String key = getLayoutDescriptor(identifier);
-        final String keyboardLayoutDescriptor;
-        synchronized (mDataStore) {
-            keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
-        }
-
-        if (keyboardLayoutDescriptor == null) {
-            return null;
-        }
-
-        final KeyboardLayout[] result = new KeyboardLayout[1];
-        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                result[0] = layout;
-            }
-        });
-        if (result[0] == null) {
-            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
-                    + keyboardLayoutDescriptor + "'.");
-        }
-        return result[0];
-    }
-
-    @Override
-    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
-            String keyboardLayoutDescriptor) {
-        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                "setKeyboardLayoutForInputDevice()")) {
-            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
-        }
-        if (keyboardLayoutDescriptor == null) {
-            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
-        }
-        if (imeInfo == null) {
-            throw new IllegalArgumentException("imeInfo must not be null");
-        }
-        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
-        setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
-    }
-
-    private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
-            InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            try {
-                if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
-                                " for subtype " + imeHandle + " and device " + identifier +
-                                " using key " + key);
-                    }
-                    if (imeHandle.equals(mCurrentImeHandle)) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "Layout for current subtype changed, switching layout");
-                        }
-                        SomeArgs args = SomeArgs.obtain();
-                        args.arg1 = identifier;
-                        args.arg2 = imeHandle;
-                        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
-                    }
-                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
-                }
-            } finally {
-                mDataStore.saveIfNeeded();
-            }
-        }
-    }
-
-    @Override // Binder call
     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
@@ -1462,7 +1381,8 @@
                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
                 }
                 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
-                        && !Objects.equals(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
+                        && !Objects.equals(oldLayout,
+                                mDataStore.getCurrentKeyboardLayout(key))) {
                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
                 }
             } finally {
@@ -1505,51 +1425,43 @@
         }
     }
 
-    // Must be called on handler.
-    private void handleSwitchInputMethodSubtype(int userId,
-            @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
-        if (DEBUG) {
-            Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
-                    + " ime=" + inputMethodInfo + " subtype=" + subtype);
-        }
-        if (inputMethodInfo == null) {
-            Slog.d(TAG, "No InputMethod is running, ignoring change");
-            return;
-        }
-        if (subtype != null && !"keyboard".equals(subtype.getMode())) {
-            Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
-            return;
-        }
-        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
-        if (!handle.equals(mCurrentImeHandle)) {
-            mCurrentImeHandle = handle;
-            handleSwitchKeyboardLayout(null, handle);
-        }
+    public void switchKeyboardLayout(int deviceId, int direction) {
+        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
     }
 
     // Must be called on handler.
-    private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
-            InputMethodSubtypeHandle handle) {
-        synchronized (mInputDevicesLock) {
-            for (InputDevice device : mInputDevices) {
-                if (identifier != null && !device.getIdentifier().equals(identifier) ||
-                        !device.isFullKeyboard()) {
-                    continue;
+    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+        final InputDevice device = getInputDevice(deviceId);
+        if (device != null) {
+            final boolean changed;
+            final String keyboardLayoutDescriptor;
+
+            String key = getLayoutDescriptor(device.getIdentifier());
+            synchronized (mDataStore) {
+                try {
+                    changed = mDataStore.switchKeyboardLayout(key, direction);
+                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
+                            key);
+                } finally {
+                    mDataStore.saveIfNeeded();
                 }
-                String key = getLayoutDescriptor(device.getIdentifier());
-                boolean changed = false;
-                synchronized (mDataStore) {
-                    try {
-                        if (mDataStore.switchKeyboardLayout(key, handle)) {
-                            changed = true;
-                        }
-                    } finally {
-                        mDataStore.saveIfNeeded();
+            }
+
+            if (changed) {
+                if (mSwitchedKeyboardLayoutToast != null) {
+                    mSwitchedKeyboardLayoutToast.cancel();
+                    mSwitchedKeyboardLayoutToast = null;
+                }
+                if (keyboardLayoutDescriptor != null) {
+                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
+                    if (keyboardLayout != null) {
+                        mSwitchedKeyboardLayoutToast = Toast.makeText(
+                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
+                        mSwitchedKeyboardLayoutToast.show();
                     }
                 }
-                if (changed) {
-                    reloadKeyboardLayouts();
-                }
+
+                reloadKeyboardLayouts();
             }
         }
     }
@@ -1790,7 +1702,7 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
         pw.println("INPUT MANAGER (dumpsys input)\n");
@@ -1798,49 +1710,8 @@
         if (dumpStr != null) {
             pw.println(dumpStr);
         }
-        pw.println("  Keyboard Layouts:");
-        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                pw.println("    \"" + layout + "\": " + layout.getDescriptor());
-            }
-        });
-        pw.println();
-        synchronized(mDataStore) {
-            mDataStore.dump(pw, "  ");
-        }
     }
 
-    @Override
-    public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ShellCallback callback,
-            ResultReceiver resultReceiver) {
-        (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
-    }
-
-    public int onShellCommand(Shell shell, String cmd) {
-        if (TextUtils.isEmpty(cmd)) {
-            shell.onHelp();
-            return 1;
-        }
-        if (cmd.equals("setlayout")) {
-            if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                    "onShellCommand()")) {
-                throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
-            }
-            InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
-                    shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
-            String descriptor = shell.getNextArgRequired();
-            int vid = Integer.decode(shell.getNextArgRequired());
-            int pid = Integer.decode(shell.getNextArgRequired());
-            InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
-            setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
-        }
-        return 0;
-    }
-
-
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -2169,12 +2040,9 @@
                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
                     deliverInputDevicesChanged((InputDevice[])msg.obj);
                     break;
-                case MSG_SWITCH_KEYBOARD_LAYOUT: {
-                    SomeArgs args = (SomeArgs)msg.obj;
-                    handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
-                            (InputMethodSubtypeHandle)args.arg2);
+                case MSG_SWITCH_KEYBOARD_LAYOUT:
+                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
                     break;
-                }
                 case MSG_RELOAD_KEYBOARD_LAYOUTS:
                     reloadKeyboardLayouts();
                     break;
@@ -2184,22 +2052,12 @@
                 case MSG_RELOAD_DEVICE_ALIASES:
                     reloadDeviceAliases();
                     break;
-                case MSG_DELIVER_TABLET_MODE_CHANGED: {
+                case MSG_DELIVER_TABLET_MODE_CHANGED:
                     SomeArgs args = (SomeArgs) msg.obj;
                     long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
                     boolean inTabletMode = (boolean) args.arg1;
                     deliverTabletModeChanged(whenNanos, inTabletMode);
                     break;
-                }
-                case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
-                    final int userId = msg.arg1;
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
-                    final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
-                    args.recycle();
-                    handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
-                    break;
-                }
             }
         }
     }
@@ -2341,25 +2199,6 @@
         }
     }
 
-    private class Shell extends ShellCommand {
-        @Override
-        public int onCommand(String cmd) {
-            return onShellCommand(this, cmd);
-        }
-
-        @Override
-        public void onHelp() {
-            final PrintWriter pw = getOutPrintWriter();
-            pw.println("Input manager commands:");
-            pw.println("  help");
-            pw.println("    Print this help text.");
-            pw.println("");
-            pw.println("  setlayout IME_ID IME_SUPTYPE_HASH_CODE"
-                    + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
-            pw.println("    Sets a keyboard layout for a given IME subtype and input device pair");
-        }
-    }
-
     private final class LocalService extends InputManagerInternal {
         @Override
         public void setDisplayViewports(DisplayViewport defaultViewport,
@@ -2380,16 +2219,6 @@
         }
 
         @Override
-        public void onInputMethodSubtypeChanged(int userId,
-                @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
-            final SomeArgs someArgs = SomeArgs.obtain();
-            someArgs.arg1 = inputMethodInfo;
-            someArgs.arg2 = subtype;
-            mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
-                    .sendToTarget();
-        }
-
-        @Override
         public void toggleCapsLock(int deviceId) {
             nativeToggleCapsLock(mPtr, deviceId);
         }
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index c9f8b20..196787a 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -16,7 +16,6 @@
 
 package com.android.server.input;
 
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
@@ -28,8 +27,6 @@
 import android.annotation.Nullable;
 import android.view.Surface;
 import android.hardware.input.TouchCalibration;
-import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
@@ -41,13 +38,10 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -139,26 +133,9 @@
         }
         return state.getKeyboardLayouts();
     }
-    public String getKeyboardLayout(String inputDeviceDescriptor,
-            InputMethodSubtypeHandle imeHandle) {
-        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
-        if (state == null) {
-            return null;
-        }
-        return state.getKeyboardLayout(imeHandle);
-    }
 
-    public boolean setKeyboardLayout(String inputDeviceDescriptor,
-            InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
-        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
-        if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) {
-            setDirty();
-            return true;
-        }
-        return false;
-    }
-
-    public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) {
+    public boolean addKeyboardLayout(String inputDeviceDescriptor,
+            String keyboardLayoutDescriptor) {
         InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
         if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
             setDirty();
@@ -177,10 +154,9 @@
         return false;
     }
 
-    public boolean switchKeyboardLayout(String inputDeviceDescriptor,
-            InputMethodSubtypeHandle imeHandle) {
+    public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
         InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
-        if (state != null && state.switchKeyboardLayout(imeHandle)) {
+        if (state != null && state.switchKeyboardLayout(direction)) {
             setDirty();
             return true;
         }
@@ -327,18 +303,6 @@
         serializer.endDocument();
     }
 
-    public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "PersistentDataStore");
-        pw.println(prefix + "  mLoaded=" + mLoaded);
-        pw.println(prefix + "  mDirty=" + mDirty);
-        pw.println(prefix + "  InputDeviceStates:");
-        int i = 0;
-        for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
-            pw.println(prefix + "    " + i++ + ": " + entry.getKey());
-            entry.getValue().dump(pw, prefix + "      ");
-        }
-    }
-
     private static final class InputDeviceState {
         private static final String[] CALIBRATION_NAME = { "x_scale",
                 "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
@@ -346,8 +310,7 @@
         private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
         @Nullable
         private String mCurrentKeyboardLayout;
-        private List<String> mUnassociatedKeyboardLayouts = new ArrayList<>();
-        private ArrayMap<InputMethodSubtypeHandle, String> mKeyboardLayouts = new ArrayMap<>();
+        private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
 
         public TouchCalibration getTouchCalibration(int surfaceRotation) {
             try {
@@ -386,34 +349,18 @@
         }
 
         public String[] getKeyboardLayouts() {
-            if (mUnassociatedKeyboardLayouts.isEmpty()) {
+            if (mKeyboardLayouts.isEmpty()) {
                 return (String[])ArrayUtils.emptyArray(String.class);
             }
-            return mUnassociatedKeyboardLayouts.toArray(
-                    new String[mUnassociatedKeyboardLayouts.size()]);
-        }
-
-        public String getKeyboardLayout(InputMethodSubtypeHandle handle) {
-            return mKeyboardLayouts.get(handle);
-        }
-
-        public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle,
-                String keyboardLayout) {
-            String existingLayout = mKeyboardLayouts.get(imeHandle);
-            if (TextUtils.equals(existingLayout, keyboardLayout)) {
-                return false;
-            }
-            mKeyboardLayouts.put(imeHandle, keyboardLayout);
-            return true;
+            return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
         }
 
         public boolean addKeyboardLayout(String keyboardLayout) {
-            int index = Collections.binarySearch(
-                    mUnassociatedKeyboardLayouts, keyboardLayout);
+            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
             if (index >= 0) {
                 return false;
             }
-            mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout);
+            mKeyboardLayouts.add(-index - 1, keyboardLayout);
             if (mCurrentKeyboardLayout == null) {
                 mCurrentKeyboardLayout = keyboardLayout;
             }
@@ -421,11 +368,11 @@
         }
 
         public boolean removeKeyboardLayout(String keyboardLayout) {
-            int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout);
+            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
             if (index < 0) {
                 return false;
             }
-            mUnassociatedKeyboardLayouts.remove(index);
+            mKeyboardLayouts.remove(index);
             updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
             return true;
         }
@@ -433,34 +380,41 @@
         private void updateCurrentKeyboardLayoutIfRemoved(
                 String removedKeyboardLayout, int removedIndex) {
             if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
-                if (!mUnassociatedKeyboardLayouts.isEmpty()) {
+                if (!mKeyboardLayouts.isEmpty()) {
                     int index = removedIndex;
-                    if (index == mUnassociatedKeyboardLayouts.size()) {
+                    if (index == mKeyboardLayouts.size()) {
                         index = 0;
                     }
-                    mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index);
+                    mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
                 } else {
                     mCurrentKeyboardLayout = null;
                 }
             }
         }
 
-        public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) {
-            final String layout = mKeyboardLayouts.get(imeHandle);
-            if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) {
-                mCurrentKeyboardLayout = layout;
-                return true;
+        public boolean switchKeyboardLayout(int direction) {
+            final int size = mKeyboardLayouts.size();
+            if (size < 2) {
+                return false;
             }
-            return false;
+            int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
+            assert index >= 0;
+            if (direction > 0) {
+                index = (index + 1) % size;
+            } else {
+                index = (index + size - 1) % size;
+            }
+            mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+            return true;
         }
 
         public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
             boolean changed = false;
-            for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) {
-                String keyboardLayout = mUnassociatedKeyboardLayouts.get(i);
+            for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
+                String keyboardLayout = mKeyboardLayouts.get(i);
                 if (!availableKeyboardLayouts.contains(keyboardLayout)) {
                     Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
-                    mUnassociatedKeyboardLayouts.remove(i);
+                    mKeyboardLayouts.remove(i);
                     updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
                     changed = true;
                 }
@@ -478,8 +432,13 @@
                         throw new XmlPullParserException(
                                 "Missing descriptor attribute on keyboard-layout.");
                     }
-
                     String current = parser.getAttributeValue(null, "current");
+                    if (mKeyboardLayouts.contains(descriptor)) {
+                        throw new XmlPullParserException(
+                                "Found duplicate keyboard layout.");
+                    }
+
+                    mKeyboardLayouts.add(descriptor);
                     if (current != null && current.equals("true")) {
                         if (mCurrentKeyboardLayout != null) {
                             throw new XmlPullParserException(
@@ -487,32 +446,6 @@
                         }
                         mCurrentKeyboardLayout = descriptor;
                     }
-
-                    String inputMethodId = parser.getAttributeValue(null, "input-method-id");
-                    String inputMethodSubtypeId =
-                        parser.getAttributeValue(null, "input-method-subtype-id");
-                    if (inputMethodId == null && inputMethodSubtypeId != null
-                            || inputMethodId != null && inputMethodSubtypeId == null) {
-                        throw new XmlPullParserException(
-                                "Found an incomplete input method description");
-                    }
-
-                    if (inputMethodSubtypeId != null) {
-                        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
-                                inputMethodId, Integer.parseInt(inputMethodSubtypeId));
-                        if (mKeyboardLayouts.containsKey(handle)) {
-                            throw new XmlPullParserException(
-                                    "Found duplicate subtype to keyboard layout mapping: "
-                                    + handle);
-                        }
-                        mKeyboardLayouts.put(handle, descriptor);
-                    } else {
-                        if (mUnassociatedKeyboardLayouts.contains(descriptor)) {
-                            throw new XmlPullParserException(
-                                    "Found duplicate unassociated keyboard layout: " + descriptor);
-                        }
-                        mUnassociatedKeyboardLayouts.add(descriptor);
-                    }
                 } else if (parser.getName().equals("calibration")) {
                     String format = parser.getAttributeValue(null, "format");
                     String rotation = parser.getAttributeValue(null, "rotation");
@@ -563,31 +496,19 @@
             }
 
             // Maintain invariant that layouts are sorted.
-            Collections.sort(mUnassociatedKeyboardLayouts);
+            Collections.sort(mKeyboardLayouts);
 
             // Maintain invariant that there is always a current keyboard layout unless
             // there are none installed.
-            if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) {
-                mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0);
+            if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
+                mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
             }
         }
 
         public void saveToXml(XmlSerializer serializer) throws IOException {
-            for (String layout : mUnassociatedKeyboardLayouts) {
+            for (String layout : mKeyboardLayouts) {
                 serializer.startTag(null, "keyboard-layout");
                 serializer.attribute(null, "descriptor", layout);
-                serializer.endTag(null, "keyboard-layout");
-            }
-
-            final int N = mKeyboardLayouts.size();
-            for (int i = 0; i < N; i++) {
-                final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i);
-                final String layout = mKeyboardLayouts.valueAt(i);
-                serializer.startTag(null, "keyboard-layout");
-                serializer.attribute(null, "descriptor", layout);
-                serializer.attribute(null, "input-method-id", handle.getInputMethodId());
-                serializer.attribute(null, "input-method-subtype-id",
-                        Integer.toString(handle.getSubtypeId()));
                 if (layout.equals(mCurrentKeyboardLayout)) {
                     serializer.attribute(null, "current", "true");
                 }
@@ -612,22 +533,6 @@
             }
         }
 
-        private void dump(final PrintWriter pw, final String prefix) {
-            pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout);
-            pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts);
-            pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration));
-            pw.println(prefix + "Subtype to Layout Mappings:");
-            final int N = mKeyboardLayouts.size();
-            if (N != 0) {
-                for (int i = 0; i < N; i++) {
-                    pw.println(prefix + "  " + mKeyboardLayouts.keyAt(i) + ": "
-                            + mKeyboardLayouts.valueAt(i));
-                }
-            } else {
-                pw.println(prefix + "  <none>");
-            }
-        }
-
         private static String surfaceRotationToString(int surfaceRotation) {
             switch (surfaceRotation) {
                 case Surface.ROTATION_0:   return "0";
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
index 08607bc..425ec47 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -48,6 +48,11 @@
     public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket);
 
     /**
+     * Tell the scheduler when a JobServiceContext starts running a job in an app
+     */
+    void noteJobStart(String packageName, int userId);
+
+    /**
      * Returns a list of pending jobs scheduled by the system service.
      */
     List<JobInfo> getSystemScheduledPendingJobs();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 0e7e540..0b1f9a6 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -88,7 +88,6 @@
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob;
-import com.android.server.job.controllers.AppIdleController;
 import com.android.server.job.controllers.BackgroundJobsController;
 import com.android.server.job.controllers.BatteryController;
 import com.android.server.job.controllers.ConnectivityController;
@@ -109,6 +108,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
@@ -239,6 +239,27 @@
     long mHeartbeat = 0;
     long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
 
+    /**
+     * Named indices into the STANDBY_BEATS array, for clarity in referring to
+     * specific buckets' bookkeeping.
+     */
+    static final int ACTIVE_INDEX = 0;
+    static final int WORKING_INDEX = 1;
+    static final int FREQUENT_INDEX = 2;
+    static final int RARE_INDEX = 3;
+
+    /**
+     * Bookkeeping about when jobs last run.  We keep our own record in heartbeat time,
+     * rather than rely on Usage Stats' timestamps, because heartbeat time can be
+     * manipulated for testing purposes and we need job runnability to track that rather
+     * than real time.
+     *
+     * Outer SparseArray slices by user handle; inner map of package name to heartbeat
+     * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys
+     * and it will be accessed in a known-hot code path.
+     */
+    final SparseArray<HashMap<String, Long>> mLastJobHeartbeats = new SparseArray<>();
+
     static final String HEARTBEAT_TAG = "*job.heartbeat*";
     final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener();
 
@@ -533,11 +554,11 @@
                     DEFAULT_MIN_EXP_BACKOFF_TIME);
             STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME,
                     DEFAULT_STANDBY_HEARTBEAT_TIME);
-            STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
+            STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
                     DEFAULT_STANDBY_WORKING_BEATS);
-            STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
+            STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
                     DEFAULT_STANDBY_FREQUENT_BEATS);
-            STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
+            STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
                     DEFAULT_STANDBY_RARE_BEATS);
             CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
                     DEFAULT_CONN_CONGESTION_DELAY_FRAC);
@@ -1051,7 +1072,8 @@
                 final JobStatus job = jsc.getRunningJobLocked();
                 if (job != null
                         && (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
-                        && !job.dozeWhitelisted) {
+                        && !job.dozeWhitelisted
+                        && !job.uidActive) {
                     // We will report active if we have a job running and it is not an exception
                     // due to being in the foreground or whitelisted.
                     active = true;
@@ -1115,7 +1137,6 @@
         mStorageController = new StorageController(this);
         mControllers.add(mStorageController);
         mControllers.add(new BackgroundJobsController(this));
-        mControllers.add(new AppIdleController(this));
         mControllers.add(new ContentObserverController(this));
         mDeviceIdleJobsController = new DeviceIdleJobsController(this);
         mControllers.add(mDeviceIdleJobsController);
@@ -1421,15 +1442,40 @@
                 periodicToReschedule.getLastFailedRunTime());
     }
 
+    /*
+     * We default to "long enough ago that every bucket's jobs are immediately runnable" to
+     * avoid starvation of apps in uncommon-use buckets that might arise from repeated
+     * reboot behavior.
+     */
     long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) {
-        final long heartbeat;
-        final long timeSinceLastJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+        // The furthest back in pre-boot time that we need to bother with
+        long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX];
+        boolean cacheHit = false;
         synchronized (mLock) {
-            heartbeat = mHeartbeat - (timeSinceLastJob / mConstants.STANDBY_HEARTBEAT_TIME);
+            HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
+            if (jobPackages != null) {
+                long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE);
+                if (cachedValue < Long.MAX_VALUE) {
+                    cacheHit = true;
+                    heartbeat = cachedValue;
+                }
+            }
+            if (!cacheHit) {
+                // We haven't seen it yet; ask usage stats about it
+                final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+                if (timeSinceJob < Long.MAX_VALUE) {
+                    // Usage stats knows about it from before, so calculate back from that
+                    // and go from there.
+                    heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME);
+                }
+                // If usage stats returned its "not found" MAX_VALUE, we still have the
+                // negative default 'heartbeat' value we established above
+                setLastJobHeartbeatLocked(packageName, userId, heartbeat);
+            }
         }
         if (DEBUG_STANDBY) {
-            Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " + packageName + "/" + userId
-                    + " delta=" + timeSinceLastJob);
+            Slog.v(TAG, "Last job heartbeat " + heartbeat + " for "
+                    + packageName + "/" + userId);
         }
         return heartbeat;
     }
@@ -1438,12 +1484,21 @@
         return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId());
     }
 
+    void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) {
+        HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
+        if (jobPackages == null) {
+            jobPackages = new HashMap<>();
+            mLastJobHeartbeats.put(userId, jobPackages);
+        }
+        jobPackages.put(packageName, heartbeat);
+    }
+
     // JobCompletedListener implementations.
 
     /**
      * A job just finished executing. We fetch the
      * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
-     * whether we want to reschedule we readd it to the controllers.
+     * whether we want to reschedule we re-add it to the controllers.
      * @param jobStatus Completed job.
      * @param needsReschedule Whether the implementing class should reschedule this job.
      */
@@ -1867,6 +1922,9 @@
         // scheduled are sitting there, not ready yet) and very cheap to check (just
         // a few conditions on data in JobStatus).
         if (!jobReady) {
+            if (job.getSourcePackageName().equals("android.jobscheduler.cts.jobtestapp")) {
+                Slog.v(TAG, "    NOT READY: " + job);
+            }
             return false;
         }
 
@@ -1905,9 +1963,21 @@
         // an appropriate amount of time since the last invocation.  During device-
         // wide parole, standby bucketing is ignored.
         //
-        // But if a job has FLAG_EXEMPT_FROM_APP_STANDBY, don't check it.
-        if (!mInParole && !job.getJob().isExemptedFromAppStandby()) {
+        // Jobs in 'active' apps are not subject to standby, nor are jobs that are
+        // specifically marked as exempt.
+        if (DEBUG_STANDBY) {
+            Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+                    + " parole=" + mInParole + " active=" + job.uidActive
+                    + " exempt=" + job.getJob().isExemptedFromAppStandby());
+        }
+        if (!mInParole
+                && !job.uidActive
+                && !job.getJob().isExemptedFromAppStandby()) {
             final int bucket = job.getStandbyBucket();
+            if (DEBUG_STANDBY) {
+                Slog.v(TAG, "  bucket=" + bucket + " heartbeat=" + mHeartbeat
+                        + " next=" + mNextBucketHeartbeat[bucket]);
+            }
             if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
                 // Only skip this job if the app is still waiting for the end of its nominal
                 // bucket interval.  Once it's waited that long, we let it go ahead and clear.
@@ -2194,6 +2264,12 @@
             return baseHeartbeat;
         }
 
+        public void noteJobStart(String packageName, int userId) {
+            synchronized (mLock) {
+                setLastJobHeartbeatLocked(packageName, userId, mHeartbeat);
+            }
+        }
+
         /**
          * Returns a list of all pending jobs. A running job is not considered pending. Periodic
          * jobs are always considered pending.
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 1f8cf76..0bb6854 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -268,10 +268,14 @@
             } catch (RemoteException e) {
                 // Whatever.
             }
+            final String jobPackage = job.getSourcePackageName();
+            final int jobUserId = job.getSourceUserId();
             UsageStatsManagerInternal usageStats =
                     LocalServices.getService(UsageStatsManagerInternal.class);
-            usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
-                    mExecutionStartTimeElapsed);
+            usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed);
+            JobSchedulerInternal jobScheduler =
+                    LocalServices.getService(JobSchedulerInternal.class);
+            jobScheduler.noteJobStart(jobPackage, jobUserId);
             mAvailable = false;
             mStoppedReason = null;
             mStoppedTime = 0;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
deleted file mode 100644
index ed29a4c..0000000
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2015 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.job.controllers;
-
-import android.app.usage.UsageStatsManagerInternal;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateControllerProto;
-
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-/**
- * Controls when apps are considered idle and if jobs pertaining to those apps should
- * be executed. Apps that haven't been actively launched or accessed from a foreground app
- * for a certain amount of time (maybe hours or days) are considered idle. When the app comes
- * out of idle state, it will be allowed to run scheduled jobs.
- */
-public final class AppIdleController extends StateController {
-    private static final String TAG = "JobScheduler.AppIdle";
-    private static final boolean DEBUG = JobSchedulerService.DEBUG
-            || Log.isLoggable(TAG, Log.DEBUG);
-
-    private final UsageStatsManagerInternal mUsageStatsInternal;
-    private boolean mInitializedParoleOn;
-    boolean mAppIdleParoleOn;
-
-    final class GlobalUpdateFunc implements Consumer<JobStatus> {
-        boolean mChanged;
-
-        @Override
-        public void accept(JobStatus jobStatus) {
-            String packageName = jobStatus.getSourcePackageName();
-            final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
-                    jobStatus.getSourceUid(), jobStatus.getSourceUserId());
-            if (DEBUG) {
-                Slog.d(TAG, "Setting idle state of " + packageName + " to " + appIdle);
-            }
-            if (jobStatus.setAppNotIdleConstraintSatisfied(!appIdle)) {
-                mChanged = true;
-            }
-        }
-    }
-
-    final static class PackageUpdateFunc implements Consumer<JobStatus> {
-        final int mUserId;
-        final String mPackage;
-        final boolean mIdle;
-        boolean mChanged;
-
-        PackageUpdateFunc(int userId, String pkg, boolean idle) {
-            mUserId = userId;
-            mPackage = pkg;
-            mIdle = idle;
-        }
-
-        @Override
-        public void accept(JobStatus jobStatus) {
-            if (jobStatus.getSourcePackageName().equals(mPackage)
-                    && jobStatus.getSourceUserId() == mUserId) {
-                if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "App Idle state changed, setting idle state of "
-                                + mPackage + " to " + mIdle);
-                    }
-                    mChanged = true;
-                }
-            }
-        }
-    }
-
-    public AppIdleController(JobSchedulerService service) {
-        super(service);
-        mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
-        mAppIdleParoleOn = true;
-        mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
-    }
-
-    @Override
-    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
-        if (!mInitializedParoleOn) {
-            mInitializedParoleOn = true;
-            mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
-        }
-        String packageName = jobStatus.getSourcePackageName();
-        final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
-                jobStatus.getSourceUid(), jobStatus.getSourceUserId());
-        if (DEBUG) {
-            Slog.d(TAG, "Start tracking, setting idle state of "
-                    + packageName + " to " + appIdle);
-        }
-        jobStatus.setAppNotIdleConstraintSatisfied(!appIdle);
-    }
-
-    @Override
-    public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
-            boolean forUpdate) {
-    }
-
-    @Override
-    public void dumpControllerStateLocked(final IndentingPrintWriter pw,
-            final Predicate<JobStatus> predicate) {
-        pw.println("Parole on: " + mAppIdleParoleOn);
-        pw.println();
-
-        mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
-            pw.print("#");
-            jobStatus.printUniqueId(pw);
-            pw.print(" from ");
-            UserHandle.formatUid(pw, jobStatus.getSourceUid());
-            pw.print(": ");
-            pw.print(jobStatus.getSourcePackageName());
-            if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) {
-                pw.println(" RUNNABLE");
-            } else {
-                pw.println(" WAITING");
-            }
-        });
-    }
-
-    @Override
-    public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
-            Predicate<JobStatus> predicate) {
-        final long token = proto.start(fieldId);
-        final long mToken = proto.start(StateControllerProto.APP_IDLE);
-
-        proto.write(StateControllerProto.AppIdleController.IS_PAROLE_ON, mAppIdleParoleOn);
-
-        mService.getJobStore().forEachJob(predicate, (js) -> {
-            final long jsToken =
-                    proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS);
-            js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO);
-            proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID,
-                    js.getSourceUid());
-            proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME,
-                    js.getSourcePackageName());
-            proto.write(
-                    StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED,
-                    (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
-            proto.end(jsToken);
-        });
-
-        proto.end(mToken);
-        proto.end(token);
-    }
-
-    void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
-        // Flag if any app's idle state has changed
-        boolean changed = false;
-        synchronized (mLock) {
-            if (mAppIdleParoleOn == isAppIdleParoleOn) {
-                return;
-            }
-            mAppIdleParoleOn = isAppIdleParoleOn;
-            GlobalUpdateFunc update = new GlobalUpdateFunc();
-            mService.getJobStore().forEachJob(update);
-            if (update.mChanged) {
-                changed = true;
-            }
-        }
-        if (changed) {
-            mStateChangedListener.onControllerStateChanged();
-        }
-    }
-
-    private final class AppIdleStateChangeListener
-            extends UsageStatsManagerInternal.AppIdleStateChangeListener {
-        @Override
-        public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket,
-                int reason) {
-            boolean changed = false;
-            synchronized (mLock) {
-                if (mAppIdleParoleOn) {
-                    return;
-                }
-
-                PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
-                mService.getJobStore().forEachJob(update);
-                if (update.mChanged) {
-                    changed = true;
-                }
-            }
-            if (changed) {
-                mStateChangedListener.onControllerStateChanged();
-            }
-        }
-
-        @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-            if (DEBUG) {
-                Slog.d(TAG, "Parole on: " + isParoleOn);
-            }
-            setAppIdleParoleOn(isParoleOn);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 36e75115..b698e5b 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -28,17 +28,32 @@
 import com.android.server.AppStateTracker.Listener;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
 import com.android.server.job.StateControllerProto;
 import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
 
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
+/**
+ * Tracks the following pieces of JobStatus state:
+ *
+ * - the CONSTRAINT_BACKGROUND_NOT_RESTRICTED general constraint bit, which
+ *    is used to selectively permit battery-saver exempted jobs to run; and
+ *
+ * - the uid-active boolean state expressed by the AppStateTracker.  Jobs in 'active'
+ *    uids are inherently eligible to run jobs regardless of the uid's standby bucket.
+ */
 public final class BackgroundJobsController extends StateController {
     private static final String TAG = "JobScheduler.Background";
     private static final boolean DEBUG = JobSchedulerService.DEBUG
             || Log.isLoggable(TAG, Log.DEBUG);
 
+    // Tri-state about possible "is this uid 'active'?" knowledge
+    static final int UNKNOWN = 0;
+    static final int KNOWN_ACTIVE = 1;
+    static final int KNOWN_INACTIVE = 2;
+
     private final AppStateTracker mAppStateTracker;
 
     public BackgroundJobsController(JobSchedulerService service) {
@@ -51,7 +66,7 @@
 
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
-        updateSingleJobRestrictionLocked(jobStatus);
+        updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
     }
 
     @Override
@@ -137,23 +152,24 @@
     }
 
     private void updateAllJobRestrictionsLocked() {
-        updateJobRestrictionsLocked(/*filterUid=*/ -1);
+        updateJobRestrictionsLocked(/*filterUid=*/ -1, UNKNOWN);
     }
 
-    private void updateJobRestrictionsForUidLocked(int uid) {
-
-        // TODO Use forEachJobForSourceUid() once we have it.
-
-        updateJobRestrictionsLocked(/*filterUid=*/ uid);
+    private void updateJobRestrictionsForUidLocked(int uid, boolean isActive) {
+        updateJobRestrictionsLocked(uid, (isActive) ? KNOWN_ACTIVE : KNOWN_INACTIVE);
     }
 
-    private void updateJobRestrictionsLocked(int filterUid) {
-        final UpdateJobFunctor updateTrackedJobs =
-                new UpdateJobFunctor(filterUid);
+    private void updateJobRestrictionsLocked(int filterUid, int newActiveState) {
+        final UpdateJobFunctor updateTrackedJobs = new UpdateJobFunctor(newActiveState);
 
         final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
 
-        mService.getJobStore().forEachJob(updateTrackedJobs);
+        final JobStore store = mService.getJobStore();
+        if (filterUid > 0) {
+            store.forEachJobForSourceUid(filterUid, updateTrackedJobs);
+        } else {
+            store.forEachJob(updateTrackedJobs);
+        }
 
         final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
         if (DEBUG) {
@@ -170,7 +186,7 @@
         }
     }
 
-    boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
+    boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, int activeState) {
 
         final int uid = jobStatus.getSourceUid();
         final String packageName = jobStatus.getSourcePackageName();
@@ -179,28 +195,32 @@
                 (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
                         != 0);
 
-        return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
+        final boolean isActive;
+        if (activeState == UNKNOWN) {
+            isActive = mAppStateTracker.isUidActive(uid);
+        } else {
+            isActive = (activeState == KNOWN_ACTIVE);
+        }
+        boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
+        didChange |= jobStatus.setUidActive(isActive);
+        return didChange;
     }
 
     private final class UpdateJobFunctor implements Consumer<JobStatus> {
-        private final int mFilterUid;
-
+        final int activeState;
         boolean mChanged = false;
         int mTotalCount = 0;
         int mCheckedCount = 0;
 
-        UpdateJobFunctor(int filterUid) {
-            mFilterUid = filterUid;
+        public UpdateJobFunctor(int newActiveState) {
+            activeState = newActiveState;
         }
 
         @Override
         public void accept(JobStatus jobStatus) {
             mTotalCount++;
-            if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
-                return;
-            }
             mCheckedCount++;
-            if (updateSingleJobRestrictionLocked(jobStatus)) {
+            if (updateSingleJobRestrictionLocked(jobStatus, activeState)) {
                 mChanged = true;
             }
         }
@@ -215,16 +235,16 @@
         }
 
         @Override
-        public void updateJobsForUid(int uid) {
+        public void updateJobsForUid(int uid, boolean isActive) {
             synchronized (mLock) {
-                updateJobRestrictionsForUidLocked(uid);
+                updateJobRestrictionsForUidLocked(uid, isActive);
             }
         }
 
         @Override
-        public void updateJobsForUidPackage(int uid, String packageName) {
+        public void updateJobsForUidPackage(int uid, String packageName, boolean isActive) {
             synchronized (mLock) {
-                updateJobRestrictionsForUidLocked(uid);
+                updateJobRestrictionsForUidLocked(uid, isActive);
             }
         }
     };
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 5616197..578a32c 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -73,7 +73,6 @@
     static final int CONSTRAINT_TIMING_DELAY = 1<<31;
     static final int CONSTRAINT_DEADLINE = 1<<30;
     static final int CONSTRAINT_CONNECTIVITY = 1<<28;
-    static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
     static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
     static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
@@ -153,6 +152,9 @@
     // Set to true if doze constraint was satisfied due to app being whitelisted.
     public boolean dozeWhitelisted;
 
+    // Set to true when the app is "active" per AppStateTracker
+    public boolean uidActive;
+
     /**
      * Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
      */
@@ -838,10 +840,6 @@
         return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
     }
 
-    boolean setAppNotIdleConstraintSatisfied(boolean state) {
-        return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
-    }
-
     boolean setContentTriggerConstraintSatisfied(boolean state) {
         return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
     }
@@ -855,6 +853,14 @@
         return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state);
     }
 
+    boolean setUidActive(final boolean newActiveState) {
+        if (newActiveState != uidActive) {
+            uidActive = newActiveState;
+            return true;
+        }
+        return false; /* unchanged */
+    }
+
     boolean setConstraintSatisfied(int constraint, boolean state) {
         boolean old = (satisfiedConstraints&constraint) != 0;
         if (old == state) {
@@ -904,13 +910,11 @@
         // NotRestrictedInBackground implicit constraint must be satisfied
         final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
                 && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
-        final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
         final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
                 || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
         final boolean notRestrictedInBg =
                 (satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0;
-        return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing
-                && notRestrictedInBg;
+        return (isConstraintsSatisfied() || deadlineSatisfied) && notDozing && notRestrictedInBg;
     }
 
     static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
@@ -990,9 +994,6 @@
         if (job.isPersisted()) {
             sb.append(" PERSISTED");
         }
-        if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) {
-            sb.append(" WAIT:APP_NOT_IDLE");
-        }
         if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
             sb.append(" WAIT:DEV_NOT_DOZING");
         }
@@ -1091,9 +1092,6 @@
         if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
             pw.print(" CONNECTIVITY");
         }
-        if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
-            pw.print(" APP_NOT_IDLE");
-        }
         if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
             pw.print(" CONTENT_TRIGGER");
         }
@@ -1133,9 +1131,6 @@
         if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY);
         }
-        if ((constraints & CONSTRAINT_APP_NOT_IDLE) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_APP_NOT_IDLE);
-        }
         if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
             proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER);
         }
@@ -1307,6 +1302,9 @@
             if (dozeWhitelisted) {
                 pw.print(prefix); pw.println("Doze whitelisted: true");
             }
+            if (uidActive) {
+                pw.print(prefix); pw.println("Uid: active");
+            }
         }
         if (trackingControllers != 0) {
             pw.print(prefix); pw.print("Tracking:");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 468ec59..74ebf3e4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -102,6 +102,7 @@
 import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.VerifyCredentialResponse;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -436,6 +437,8 @@
         mStrongAuthTracker.register(mStrongAuth);
 
         mSpManager = injector.getSyntheticPasswordManager(mStorage);
+
+        LocalServices.addService(LockSettingsInternal.class, new LocalService());
     }
 
     /**
@@ -1041,14 +1044,10 @@
 
     private boolean isUserSecure(int userId) {
         synchronized (mSpManager) {
-            try {
-                if (isSyntheticPasswordBasedCredentialLocked(userId)) {
-                    long handle = getSyntheticPasswordHandleLocked(userId);
-                    return mSpManager.getCredentialType(handle, userId) !=
-                            LockPatternUtils.CREDENTIAL_TYPE_NONE;
-                }
-            } catch (RemoteException e) {
-                // fall through
+            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+                long handle = getSyntheticPasswordHandleLocked(userId);
+                return mSpManager.getCredentialType(handle, userId) !=
+                        LockPatternUtils.CREDENTIAL_TYPE_NONE;
             }
         }
         return mStorage.hasCredential(userId);
@@ -2305,7 +2304,7 @@
                 SyntheticPasswordManager.DEFAULT_HANDLE, userId);
     }
 
-    private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
+    private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
         if (userId == USER_FRP) {
             final int type = mStorage.readPersistentDataBlock().type;
             return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
@@ -2318,7 +2317,7 @@
     }
 
     @VisibleForTesting
-    protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
+    protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
         long handle = getSyntheticPasswordHandleLocked(userId);
         // This is a global setting
         long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
@@ -2326,7 +2325,7 @@
         return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
     }
 
-    private void enableSyntheticPasswordLocked() throws RemoteException {
+    private void enableSyntheticPasswordLocked() {
         setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
     }
 
@@ -2525,9 +2524,7 @@
         mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
     }
 
-    @Override
-    public long addEscrowToken(byte[] token, int userId) throws RemoteException {
-        ensureCallerSystemUid();
+    private long addEscrowToken(byte[] token, int userId) throws RemoteException {
         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
         synchronized (mSpManager) {
             enableSyntheticPasswordLocked();
@@ -2559,7 +2556,7 @@
         }
     }
 
-    private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
+    private void activateEscrowTokens(AuthenticationToken auth, int userId) {
         if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
         synchronized (mSpManager) {
             disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
@@ -2570,17 +2567,13 @@
         }
     }
 
-    @Override
-    public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
-        ensureCallerSystemUid();
+    private boolean isEscrowTokenActive(long handle, int userId) {
         synchronized (mSpManager) {
             return mSpManager.existsHandle(handle, userId);
         }
     }
 
-    @Override
-    public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
-        ensureCallerSystemUid();
+    private boolean removeEscrowToken(long handle, int userId) {
         synchronized (mSpManager) {
             if (handle == getSyntheticPasswordHandleLocked(userId)) {
                 Slog.w(TAG, "Cannot remove password handle");
@@ -2598,10 +2591,8 @@
         }
     }
 
-    @Override
-    public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+    private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
             byte[] token, int requestedQuality, int userId) throws RemoteException {
-        ensureCallerSystemUid();
         boolean result;
         synchronized (mSpManager) {
             if (!mSpManager.hasEscrowData(userId)) {
@@ -2650,10 +2641,8 @@
         return true;
     }
 
-    @Override
-    public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
+    private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
             throws RemoteException {
-        ensureCallerSystemUid();
         AuthenticationResult authResult;
         synchronized (mSpManager) {
             if (!mSpManager.hasEscrowData(userId)) {
@@ -2663,11 +2652,12 @@
                     tokenHandle, token, userId);
             if (authResult.authToken == null) {
                 Slog.w(TAG, "Invalid escrow token supplied");
-                return;
+                return false;
             }
         }
         unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
         onAuthTokenKnownForUser(userId, authResult.authToken);
+        return true;
     }
 
     @Override
@@ -2732,20 +2722,11 @@
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 mSpManager.destroyEscrowData(userId);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private void ensureCallerSystemUid() throws SecurityException {
-        final int callingUid = mInjector.binderGetCallingUid();
-        if (callingUid != Process.SYSTEM_UID) {
-            throw new SecurityException("Only system can call this API.");
-        }
-    }
-
     private class DeviceProvisionedObserver extends ContentObserver {
         private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
                 Settings.Global.DEVICE_PROVISIONED);
@@ -2834,4 +2815,46 @@
                     Settings.Global.DEVICE_PROVISIONED, 0) != 0;
         }
     }
+
+    private final class LocalService extends LockSettingsInternal {
+
+        @Override
+        public long addEscrowToken(byte[] token, int userId) {
+            try {
+                return LockSettingsService.this.addEscrowToken(token, userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public boolean removeEscrowToken(long handle, int userId) {
+            return LockSettingsService.this.removeEscrowToken(handle, userId);
+        }
+
+        @Override
+        public boolean isEscrowTokenActive(long handle, int userId) {
+            return LockSettingsService.this.isEscrowTokenActive(handle, userId);
+        }
+
+        @Override
+        public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+                byte[] token, int requestedQuality, int userId) {
+            try {
+                return LockSettingsService.this.setLockCredentialWithToken(credential, type,
+                        tokenHandle, token, requestedQuality, userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+            try {
+                return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index e5fc6e5..6907c58 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -39,6 +39,7 @@
 import com.android.internal.net.INetworkWatchlistManager;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.net.BaseNetdEventCallback;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -139,7 +140,7 @@
                 ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
     }
 
-    private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+    private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
         @Override
         public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
                 long timestamp, int uid) {
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index d8a30ae..d91d541 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -15,6 +15,8 @@
 */
 package com.android.server.notification;
 
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
 import android.content.Context;
 import android.util.Slog;
 
@@ -54,6 +56,11 @@
             }
         }
 
+        if (record.isIntercepted()
+                && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_BADGE) != 0) {
+            record.setShowBadge(false);
+        }
+
         return null;
     }
 
@@ -64,6 +71,5 @@
 
     @Override
     public void setZenHelper(ZenModeHelper helper) {
-
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cd387b0..b9fb2e0 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,6 +22,16 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -60,8 +70,6 @@
 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -1342,6 +1350,7 @@
             @Override
             void onPolicyChanged() {
                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
+                mRankingHandler.requestSort();
             }
         });
         mRankingHelper = new RankingHelper(getContext(),
@@ -1773,25 +1782,105 @@
      * 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);
     }
 
+    protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
+            int targetSdkVersion) {
+        if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
+            return incomingPolicy.suppressedVisualEffects;
+        }
+        final int[] effectsIntroducedInP = {
+                SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+                SUPPRESSED_EFFECT_LIGHTS,
+                SUPPRESSED_EFFECT_PEEK,
+                SUPPRESSED_EFFECT_STATUS_BAR,
+                SUPPRESSED_EFFECT_BADGE,
+                SUPPRESSED_EFFECT_AMBIENT,
+                SUPPRESSED_EFFECT_NOTIFICATION_LIST
+        };
+
+        int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
+        if (targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
+            // unset higher order bits introduced in P, maintain the user's higher order bits
+            for (int i = 0; i < effectsIntroducedInP.length ; i++) {
+                newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
+                newSuppressedVisualEffects |=
+                        (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
+            }
+            // set higher order bits according to lower order bits
+            if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+                newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+                newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+                newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+            }
+            if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+                newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+            }
+        } else {
+            boolean hasNewEffects = (newSuppressedVisualEffects
+                    - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
+            // if any of the new effects introduced in P are set
+            if (hasNewEffects) {
+                // clear out the deprecated effects
+                newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
+                        | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+                // set the deprecated effects according to the new more specific effects
+                if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
+                }
+                if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
+                        && (newSuppressedVisualEffects
+                        & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
+                        && (newSuppressedVisualEffects
+                        & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
+                }
+            } else {
+                // set higher order bits according to lower order bits
+                if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+                }
+                if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+                    newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+                }
+            }
+        }
+
+        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;
@@ -3063,10 +3152,9 @@
             try {
                 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
                         0, UserHandle.getUserId(MY_UID));
+                Policy currPolicy = mZenModeHelper.getNotificationPolicy();
 
                 if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
-                    Policy currPolicy = mZenModeHelper.getNotificationPolicy();
-
                     int priorityCategories = policy.priorityCategories;
                     // ignore alarm and media values from new policy
                     priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
@@ -3084,11 +3172,13 @@
                             policy.priorityCallSenders, policy.priorityMessageSenders,
                             policy.suppressedVisualEffects);
                 }
+                int newVisualEffects = calculateSuppressedVisualEffects(
+                            policy, currPolicy, applicationInfo.targetSdkVersion);
+                policy = new Policy(policy.priorityCategories,
+                        policy.priorityCallSenders, policy.priorityMessageSenders,
+                        newVisualEffects);
 
-                Slog.i(TAG, "setNotificationPolicy pkg=" + pkg
-                        + " targetSdk=" + applicationInfo.targetSdkVersion
-                        + " policy="
-                        + Policy.priorityCategoriesToString(policy.priorityCategories));
+                ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
                 mZenModeHelper.setNotificationPolicy(policy);
             } catch (RemoteException e) {
             } finally {
@@ -4267,6 +4357,7 @@
                     }
 
                     buzzBeepBlinkLocked(r);
+                    maybeRecordInterruptionLocked(r);
                 } finally {
                     int N = mEnqueuedNotifications.size();
                     for (int i = 0; i < N; i++) {
@@ -4465,8 +4556,7 @@
         // release the light
         boolean wasShowLights = mLights.remove(key);
         if (record.getLight() != null && aboveThreshold
-                && ((record.getSuppressedVisualEffects()
-                & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
+                && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
             mLights.add(key);
             updateLightsLocked();
             if (mUseAttentionLight) {
@@ -4477,6 +4567,7 @@
             updateLightsLocked();
         }
         if (buzz || beep || blink) {
+            record.setInterruptive(true);
             MetricsLogger.action(record.getLogMaker()
                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                     .setType(MetricsEvent.TYPE_OPEN)
@@ -4864,11 +4955,8 @@
     private void applyZenModeLocked(NotificationRecord record) {
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
         if (record.isIntercepted()) {
-            int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
-                    ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
-                    | (mZenModeHelper.shouldSuppressWhenScreenOn()
-                    ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
-            record.setSuppressedVisualEffects(suppressed);
+            record.setSuppressedVisualEffects(
+                    mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
         } else {
             record.setSuppressedVisualEffects(0);
         }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 8d2f0dd..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()));
@@ -712,13 +714,8 @@
         return Objects.equals(getNotification().category, category);
     }
 
-    public boolean isAudioStream(int stream) {
-        return getNotification().audioStreamType == stream;
-    }
-
     public boolean isAudioAttributesUsage(int usage) {
-        final AudioAttributes attributes = getNotification().audioAttributes;
-        return attributes != null && attributes.getUsage() == usage;
+        return mAttributes != null && mAttributes.getUsage() == usage;
     }
 
     /**
@@ -893,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/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index f7efff0f..6760875 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import android.app.NotificationManager;
 import android.content.ComponentName;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -60,6 +61,7 @@
     private static final int TYPE_DISABLE_EFFECTS = 13;
     private static final int TYPE_SUPPRESSOR_CHANGED = 14;
     private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
+    private static final int TYPE_SET_NOTIFICATION_POLICY = 16;
 
     private static int sNext;
     private static int sSize;
@@ -108,6 +110,12 @@
         append(TYPE_EXIT_CONDITION, c + "," + componentToString(component) + "," + reason);
     }
 
+    public static void traceSetNotificationPolicy(String pkg, int targetSdk,
+            NotificationManager.Policy policy) {
+        append(TYPE_SET_NOTIFICATION_POLICY, "pkg=" + pkg + " targetSdk=" + targetSdk
+                + " NotificationPolicy=" + policy.toString());
+    }
+
     public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
         append(TYPE_SUBSCRIBE, uri + "," + subscribeResult(provider, e));
     }
@@ -160,6 +168,7 @@
             case TYPE_DISABLE_EFFECTS: return "disable_effects";
             case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
             case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
+            case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy";
             default: return "unknown";
         }
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeExtractor.java b/services/core/java/com/android/server/notification/ZenModeExtractor.java
index 74f9806..a0aa1c3 100644
--- a/services/core/java/com/android/server/notification/ZenModeExtractor.java
+++ b/services/core/java/com/android/server/notification/ZenModeExtractor.java
@@ -16,8 +16,8 @@
 
 package com.android.server.notification;
 
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 
 import android.content.Context;
 import android.util.Log;
@@ -49,11 +49,8 @@
 
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
         if (record.isIntercepted()) {
-            int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
-                    ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
-                    | (mZenModeHelper.shouldSuppressWhenScreenOn()
-                    ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
-            record.setSuppressedVisualEffects(suppressed);
+            record.setSuppressedVisualEffects(
+                    mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
         } else {
             record.setSuppressedVisualEffects(0);
         }
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index a0003a5..71cee05 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -16,7 +16,10 @@
 
 package com.android.server.notification;
 
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
 import android.app.Notification;
+import android.app.NotificationManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.media.AudioAttributes;
@@ -30,6 +33,9 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.util.NotificationMessagingUtil;
+
 import java.io.PrintWriter;
 import java.util.Date;
 import java.util.Objects;
@@ -43,9 +49,16 @@
     private final Context mContext;
 
     private ComponentName mDefaultPhoneApp;
+    private final NotificationMessagingUtil mMessagingUtil;
 
     public ZenModeFiltering(Context context) {
         mContext = context;
+        mMessagingUtil = new NotificationMessagingUtil(mContext);
+    }
+
+    public ZenModeFiltering(Context context, NotificationMessagingUtil messagingUtil) {
+        mContext = context;
+        mMessagingUtil = messagingUtil;
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -104,6 +117,16 @@
     }
 
     public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
+        if (zen == ZEN_MODE_OFF) {
+            return false;
+        }
+        // Make an exception to policy for the notification saying that policy has changed
+        if (NotificationManager.Policy.areAllVisualEffectsSuppressed(config.suppressedVisualEffects)
+                && "android".equals(record.sbn.getPackageName())
+                && SystemMessageProto.SystemMessage.NOTE_ZEN_UPGRADE == record.sbn.getId()) {
+            ZenLog.traceNotIntercepted(record, "systemDndChangedNotification");
+            return false;
+        }
         switch (zen) {
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
                 // #notevenalarms
@@ -192,9 +215,8 @@
         return false;
     }
 
-    private static boolean isAlarm(NotificationRecord record) {
+    protected static boolean isAlarm(NotificationRecord record) {
         return record.isCategory(Notification.CATEGORY_ALARM)
-                || record.isAudioStream(AudioManager.STREAM_ALARM)
                 || record.isAudioAttributesUsage(AudioAttributes.USAGE_ALARM);
     }
 
@@ -234,17 +256,8 @@
                 && pkg.equals(mDefaultPhoneApp.getPackageName());
     }
 
-    @SuppressWarnings("deprecation")
-    private boolean isDefaultMessagingApp(NotificationRecord record) {
-        final int userId = record.getUserId();
-        if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
-        final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(),
-                Secure.SMS_DEFAULT_APPLICATION, userId);
-        return Objects.equals(defaultApp, record.sbn.getPackageName());
-    }
-
-    private boolean isMessage(NotificationRecord record) {
-        return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
+    protected boolean isMessage(NotificationRecord record) {
+        return mMessagingUtil.isMessaging(record.sbn);
     }
 
     private static boolean audienceMatches(int source, float contactAffinity) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 28d692a..aa1f7d95 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -602,7 +602,8 @@
             pw.println(config);
             return;
         }
-        pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
+        pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
+                + "messages=%b,messagesFrom=%s,"
                 + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
                 config.allowAlarms, config.allowMedia, config.allowSystem,
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
@@ -610,6 +611,7 @@
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
                 config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
                 config.allowWhenScreenOn);
+        pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
         final int N = config.automaticRules.size();
@@ -623,7 +625,7 @@
             throws XmlPullParserException, IOException {
         final ZenModeConfig config = ZenModeConfig.readXml(parser);
         if (config != null) {
-            if (config.version < ZenModeConfig.XML_VERSION) {
+            if (config.version < ZenModeConfig.XML_VERSION || forRestore) {
                 Settings.Global.putInt(mContext.getContentResolver(),
                         Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
             }
@@ -1176,8 +1178,7 @@
 
     @VisibleForTesting
     protected Notification createZenUpgradeNotification() {
-        Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
-                .setPackage("com.android.settings")
+        Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         final Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fdba99e..707184f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2592,7 +2592,7 @@
                     | SCAN_AS_PRIVILEGED,
                     0);
 
-            // Collected privileged system packages.
+            // Collect privileged system packages.
             final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
             scanDirTracedLI(privilegedAppDir,
                     mDefParseFlags
@@ -2611,7 +2611,7 @@
                     | SCAN_AS_SYSTEM,
                     0);
 
-            // Collected privileged vendor packages.
+            // Collect privileged vendor packages.
             File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
             try {
                 privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
@@ -2642,6 +2642,40 @@
                     | SCAN_AS_VENDOR,
                     0);
 
+            // Collect privileged odm packages. /odm is another vendor partition
+            // other than /vendor.
+            File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
+                        "priv-app");
+            try {
+                privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(privilegedOdmAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_VENDOR
+                    | SCAN_AS_PRIVILEGED,
+                    0);
+
+            // Collect ordinary odm packages. /odm is another vendor partition
+            // other than /vendor.
+            File odmAppDir = new File(Environment.getOdmDirectory(), "app");
+            try {
+                odmAppDir = odmAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(odmAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_VENDOR,
+                    0);
+
             // Collect all OEM packages.
             final File oemAppDir = new File(Environment.getOemDirectory(), "app");
             scanDirTracedLI(oemAppDir,
@@ -3371,6 +3405,13 @@
         // "/data/system/package_cache/1"
         File cacheDir = FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
 
+        if (cacheDir == null) {
+            // Something went wrong. Attempt to delete everything and return.
+            Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir);
+            FileUtils.deleteContentsAndDir(cacheBaseDir);
+            return null;
+        }
+
         // The following is a workaround to aid development on non-numbered userdebug
         // builds or cases where "adb sync" is used on userdebug builds. If we detect that
         // the system partition is newer.
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 054f614..407ceb7 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -125,6 +125,9 @@
      */
     public void fixSeInfoLocked() {
         final List<PackageParser.Package> pkgList = getPackages();
+        if (pkgList == null || pkgList.size() == 0) {
+            return;
+        }
 
         for (PackageParser.Package pkg : pkgList) {
             if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dda25bb..2d4438d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3881,6 +3881,15 @@
             hideRecentApps(true, false);
         }
 
+        // Handle keyboard layout switching.
+        // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
+        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
+                && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
+            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+            return -1;
+        }
+
         // Handle input method switching.
         if (down && repeatCount == 0
                 && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
@@ -5096,11 +5105,12 @@
                         pf.set(displayFrames.mOverscan);
                     } else if (canHideNavigationBar()
                             && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
-                            && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+                            && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
+                            || type == TYPE_VOLUME_OVERLAY)) {
                         // Asking for layout as if the nav bar is hidden, lets the application
                         // extend into the unrestricted overscan screen area. We only do this for
-                        // application windows to ensure no window that can be above the nav bar can
-                        // do this.
+                        // application windows and certain system windows to ensure no window that
+                        // can be above the nav bar can do this.
                         df.set(displayFrames.mOverscan);
                         pf.set(displayFrames.mOverscan);
                         // We need to tell the app about where the frame inside the overscan is, so
@@ -5160,15 +5170,6 @@
                     if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
                             "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
                             pf.left, pf.top, pf.right, pf.bottom));
-                } else if (type == TYPE_VOLUME_OVERLAY) {
-                    // Volume overlay covers everything, including the status and navbar
-                    cf.set(displayFrames.mUnrestricted);
-                    of.set(displayFrames.mUnrestricted);
-                    df.set(displayFrames.mUnrestricted);
-                    pf.set(displayFrames.mUnrestricted);
-                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
-                                    pf.left, pf.top, pf.right, pf.bottom));
                 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
                     of.set(displayFrames.mUnrestricted);
@@ -5252,8 +5253,8 @@
                         "): normal window");
                 // Otherwise, a normal window must be placed inside the content
                 // of all screen decorations.
-                if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_VOLUME_OVERLAY) {
-                    // Status bar panels and the volume dialog are the only windows who can go on
+                if (type == TYPE_STATUS_BAR_PANEL) {
+                    // Status bar panels can go on
                     // top of the status bar. They are protected by the STATUS_BAR_SERVICE
                     // permission, so they have the same privileges as the status bar itself.
                     cf.set(displayFrames.mRestricted);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index a562e34..8ec8c5b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -546,6 +546,12 @@
         public int getCameraLensCoverState();
 
         /**
+         * Switch the keyboard layout for the given device.
+         * Direction should be +1 or -1 to go to the next or previous keyboard layout.
+         */
+        public void switchKeyboardLayout(int deviceId, int direction);
+
+        /**
          * Switch the input method, to be precise, input method subtype.
          *
          * @param forwardDirection {@code true} to rotate in a forward direction.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f77b0ee..055e6ea 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -68,7 +68,6 @@
 import android.service.dreams.DreamManagerInternal;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.util.EventLog;
 import android.util.KeyValueListParser;
 import android.util.MathUtils;
 import android.util.PrintWriterPrinter;
@@ -488,6 +487,9 @@
     // The screen brightness to use while dozing.
     private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT;
 
+    // Keep display state when dozing.
+    private boolean mDrawWakeLockOverrideFromSidekick;
+
     // Time when we last logged a warning about calling userActivity() without permission.
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
@@ -1487,7 +1489,7 @@
                         break;
                 }
             }
-            EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
+            EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
 
             // Skip dozing if requested.
             if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
@@ -1572,7 +1574,7 @@
         final long now = SystemClock.uptimeMillis();
         final long savedWakeTimeMs = mOverriddenTimeout - now;
         if (savedWakeTimeMs >= 0) {
-            EventLog.writeEvent(EventLogTags.POWER_SOFT_SLEEP_REQUESTED, savedWakeTimeMs);
+            EventLogTags.writePowerSoftSleepRequested(savedWakeTimeMs);
             mOverriddenTimeout = -1;
         }
     }
@@ -2424,7 +2426,8 @@
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                 mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
-                if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+                if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+                        && !mDrawWakeLockOverrideFromSidekick) {
                     if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
                         mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                     }
@@ -3157,6 +3160,7 @@
         synchronized (mLock) {
             if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
                 mUserActivityTimeoutOverrideFromWindowManager = timeoutMillis;
+                EventLogTags.writeUserActivityTimeoutOverride(timeoutMillis);
                 mDirty |= DIRTY_SETTINGS;
                 updatePowerStateLocked();
             }
@@ -3176,6 +3180,16 @@
         }
     }
 
+    private void setDrawWakeLockOverrideFromSidekickInternal(boolean keepState) {
+        synchronized (mLock) {
+            if (mDrawWakeLockOverrideFromSidekick != keepState) {
+                mDrawWakeLockOverrideFromSidekick = keepState;
+                mDirty |= DIRTY_SETTINGS;
+                updatePowerStateLocked();
+            }
+        }
+    }
+
     @VisibleForTesting
     void setVrModeEnabled(boolean enabled) {
         mIsVrModeEnabled = enabled;
@@ -3381,6 +3395,7 @@
                     + mUserInactiveOverrideFromWindowManager);
             pw.println("  mDozeScreenStateOverrideFromDreamManager="
                     + mDozeScreenStateOverrideFromDreamManager);
+            pw.println("  mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
             pw.println("  mDozeScreenBrightnessOverrideFromDreamManager="
                     + mDozeScreenBrightnessOverrideFromDreamManager);
             pw.println("  mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
@@ -3717,6 +3732,10 @@
                     mDozeScreenStateOverrideFromDreamManager);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto
+                            .DRAW_WAKE_LOCK_OVERRIDE_FROM_SIDEKICK,
+                    mDrawWakeLockOverrideFromSidekick);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
                             .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
                     mDozeScreenBrightnessOverrideFromDreamManager);
 
@@ -4703,6 +4722,11 @@
         }
 
         @Override
+        public void setDrawWakeLockOverrideFromSidekick(boolean keepState) {
+            setDrawWakeLockOverrideFromSidekickInternal(keepState);
+        }
+
+        @Override
         public void setMaximumScreenOffTimeoutFromDeviceAdmin(@UserIdInt int userId, long timeMs) {
             setMaximumScreenOffTimeoutFromDeviceAdminInternal(userId, timeMs);
         }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 64a2570..954627b 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -73,6 +73,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
@@ -196,6 +197,7 @@
     @Override
     public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
                                         long subscriptionId, long subscriptionRuleId,
+                                        String[] cookies,
                                         StatsDimensionsValue dimensionsValue) {
         enforceCallingPermission();
         IntentSender intentSender = new IntentSender(intentSenderBinder);
@@ -205,10 +207,17 @@
                 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
                 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
                 .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
+
+        ArrayList<String> cookieList = new ArrayList<>(cookies.length);
+        for (String cookie : cookies) { cookieList.add(cookie); }
+        intent.putStringArrayListExtra(
+                StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
+
         if (DEBUG) {
-            Slog.d(TAG, String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s}",
-                    configUid, configKey, subscriptionId,
-                    subscriptionRuleId, dimensionsValue));
+            Slog.d(TAG, String.format(
+                    "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
+                    configUid, configKey, subscriptionId, subscriptionRuleId,
+                    Arrays.toString(cookies), dimensionsValue));
         }
         try {
             intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
@@ -278,7 +287,7 @@
                     && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                 return; // Keep only replacing or normal add and remove.
             }
-            Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
+            if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated.");
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
                     Slog.w(TAG, "Could not access statsd to inform it of an app update");
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/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index f7344b2..39b886d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,12 +29,12 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.view.IRecentsAnimationController;
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationTarget;
@@ -175,7 +175,7 @@
      * because it may call cancelAnimation() which needs to properly clean up the controller
      * in the window manager.
      */
-    public void initialize() {
+    public void initialize(SparseBooleanArray recentTaskIds) {
         // Make leashes for each of the visible tasks and add it to the recents animation to be
         // started
         final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
@@ -189,7 +189,7 @@
                     || config.getActivityType() == ACTIVITY_TYPE_HOME) {
                 continue;
             }
-            addAnimation(task);
+            addAnimation(task, !recentTaskIds.get(task.mTaskId));
         }
 
         // Skip the animation if there is nothing to animate
@@ -216,11 +216,12 @@
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
 
-    private void addAnimation(Task task) {
+    private void addAnimation(Task task, boolean isRecentTaskInvisible) {
         if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
         final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
                 mService);
-        final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
+        final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
+                isRecentTaskInvisible);
         anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
         task.commitPendingTransaction();
         mPendingAnimations.add(taskAdapter);
@@ -343,12 +344,14 @@
 
     private class TaskAnimationAdapter implements AnimationAdapter {
 
-        private Task mTask;
+        private final Task mTask;
         private SurfaceControl mCapturedLeash;
         private OnAnimationFinishedCallback mCapturedFinishCallback;
+        private final boolean mIsRecentTaskInvisible;
 
-        TaskAnimationAdapter(Task task) {
+        TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
             mTask = task;
+            mIsRecentTaskInvisible = isRecentTaskInvisible;
         }
 
         RemoteAnimationTarget createRemoteAnimationApp() {
@@ -361,7 +364,7 @@
             return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
                     !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
                     mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
-                    mTask.getWindowConfiguration());
+                    mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index e4bb043..169d65e 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -214,7 +214,7 @@
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
                     mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
-                    task.getWindowConfiguration());
+                    task.getWindowConfiguration(), false /*isNotInRecents*/);
         }
 
         private int getMode() {
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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 80dab22..563d792 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -181,6 +181,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
@@ -2662,11 +2663,12 @@
 
     public void initializeRecentsAnimation(
             IRecentsAnimationRunner recentsAnimationRunner,
-            RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) {
+            RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId,
+            SparseBooleanArray recentTaskIds) {
         synchronized (mWindowMap) {
             mRecentsAnimationController = new RecentsAnimationController(this,
                     recentsAnimationRunner, callbacks, displayId);
-            mRecentsAnimationController.initialize();
+            mRecentsAnimationController.initialize(recentTaskIds);
         }
     }
 
@@ -3180,6 +3182,12 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
+    public void switchKeyboardLayout(int deviceId, int direction) {
+        mInputManager.switchKeyboardLayout(deviceId, direction);
+    }
+
+    // Called by window manager policy.  Not exposed externally.
+    @Override
     public void switchInputMethod(boolean forwardDirection) {
         final InputMethodManagerInternal inputMethodManagerInternal =
                 LocalServices.getService(InputMethodManagerInternal.class);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 145aee9..f01dc20 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -694,6 +694,7 @@
         mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
         mWindowId = new WindowId(this);
         mAttrs.copyFrom(a);
+        mLastSurfaceInsets.set(mAttrs.surfaceInsets);
         mViewVisibility = viewVisibility;
         mPolicy = mService.mPolicy;
         mContext = mService.mContext;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 0aaf32c..0967652 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -30,6 +30,7 @@
 import android.util.Slog;
 
 import com.android.server.ServiceThread;
+import com.android.server.net.BaseNetdEventCallback;
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -50,7 +51,7 @@
     private ServiceThread mHandlerThread;
     private NetworkLoggingHandler mNetworkLoggingHandler;
 
-    private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+    private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
         @Override
         public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
                 long timestamp, int uid) {
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
index 3d2d8af..bbec7af 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -60,7 +60,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mTransportClientManager = new TransportClientManager(mContext);
+        mTransportClientManager = new TransportClientManager(mContext, new TransportStats());
         mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
         mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
 
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 5b65473..49ef581f 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -88,6 +88,7 @@
     @Mock private TransportConnectionListener mTransportConnectionListener;
     @Mock private TransportConnectionListener mTransportConnectionListener2;
     @Mock private IBackupTransport.Stub mTransportBinder;
+    private TransportStats mTransportStats;
     private TransportClient mTransportClient;
     private ComponentName mTransportComponent;
     private String mTransportString;
@@ -105,10 +106,12 @@
         mTransportComponent =
                 new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
         mTransportString = mTransportComponent.flattenToShortString();
+        mTransportStats = new TransportStats();
         mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
         mTransportClient =
                 new TransportClient(
                         mContext,
+                        mTransportStats,
                         mBindIntent,
                         mTransportComponent,
                         "1",
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 356e64b..0ca0a1a 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -15,6 +15,7 @@
     frameworks-base-testutils \
     services.accessibility \
     services.appwidget \
+    services.autofill \
     services.backup \
     services.core \
     services.devicepolicy \
diff --git a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index b62f1ce..5daacd7 100644
--- a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -729,8 +730,8 @@
     private void assertNoCallbacks(Listener l) throws Exception {
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -752,8 +753,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -766,8 +767,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(1)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -796,8 +797,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -808,8 +809,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -819,8 +820,8 @@
         setAppOps(UID_10_2, PACKAGE_2, false);
 
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -835,8 +836,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -849,8 +850,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(1)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -864,8 +865,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -876,8 +877,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(1)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -889,8 +890,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -901,8 +902,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -915,8 +916,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -928,8 +929,8 @@
         waitUntilMainHandlerDrain();
         // Called once for updating all whitelist and once for updating temp whitelist
         verify(l, times(2)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -940,8 +941,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(1)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -953,8 +954,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -965,8 +966,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(anyInt());
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -985,8 +986,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -997,8 +998,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1009,8 +1010,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1021,8 +1022,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1035,8 +1036,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
-        verify(l, times(0)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(1)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1047,8 +1048,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1059,8 +1060,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1071,8 +1072,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1083,8 +1084,8 @@
 
         waitUntilMainHandlerDrain();
         verify(l, times(0)).updateAllJobs();
-        verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
-        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+        verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+        verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
 
         verify(l, times(0)).unblockAllUnrestrictedAlarms();
         verify(l, times(0)).unblockAlarmsForUid(anyInt());
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..ac212ddc 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/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index fdabfb4..5906db3 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -30,6 +30,7 @@
 import android.app.IApplicationThread;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.WindowLayout;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.graphics.Rect;
@@ -39,6 +40,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Gravity;
 
 import org.junit.runner.RunWith;
 import org.junit.Test;
@@ -52,6 +54,7 @@
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyObject;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -64,6 +67,8 @@
 
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.am.ActivityStarter.Factory;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
+import com.android.server.am.TaskRecord.TaskRecordFactory;
 
 /**
  * Tests for the {@link ActivityStarter} class.
@@ -207,7 +212,8 @@
 
         if (aInfo != null) {
             aInfo.applicationInfo = new ApplicationInfo();
-            aInfo.applicationInfo.packageName = builder.getDefaultComponentPackageName();
+            aInfo.applicationInfo.packageName =
+                    ActivityBuilder.getDefaultComponent().getPackageName();
         }
 
         // Offset uid by one from {@link ActivityInfo} to simulate different uids.
@@ -284,9 +290,85 @@
         }
     }
 
-// TODO(b/69270257): Add test to verify task layout is passed additional data such as activity and
-// source.
-//    @Test
-//    public void testCreateTaskLayout() {
-//    }
+    private ActivityStarter prepareStarter() {
+        // always allow test to start activity.
+        doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
+                any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
+                anyBoolean(), any(), any(), any());
+
+        // instrument the stack and task used.
+        final ActivityStack stack = spy(mService.mStackSupervisor.getDefaultDisplay().createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */));
+        final TaskRecord task =
+                spy(new TaskBuilder(mService.mStackSupervisor).setStack(stack).build());
+
+        // supervisor needs a focused stack.
+        mService.mStackSupervisor.mFocusedStack = task.getStack();
+
+        // use factory that only returns spy task.
+        final TaskRecordFactory factory = mock(TaskRecordFactory.class);
+        TaskRecord.setTaskRecordFactory(factory);
+
+        // return task when created.
+        doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
+
+        // direct starter to use spy stack.
+        doReturn(stack).when(mService.mStackSupervisor)
+                .getLaunchStack(any(), any(), any(), anyBoolean());
+        doReturn(stack).when(mService.mStackSupervisor)
+                .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+
+        // ignore the start request.
+        doNothing().when(stack)
+                .startActivityLocked(any(), any(), anyBoolean(), anyBoolean(), any());
+
+        // ignore requests to create window container.
+        doNothing().when(task).createWindowContainer(anyBoolean(), anyBoolean());
+
+        return new ActivityStarter(mController, mService,
+                mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+    }
+
+    /**
+     * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
+     * when we are laying out a new task.
+     */
+    @Test
+    public void testCreateTaskLayout() {
+        // modifier for validating passed values.
+        final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
+        mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
+
+        // add custom values to activity info to make unique.
+        final ActivityInfo info = new ActivityInfo();
+        final Rect launchBounds = new Rect(0, 0, 20, 30);
+        final Intent intent = new Intent();
+
+        intent.setComponent(ActivityBuilder.getDefaultComponent());
+
+        final WindowLayout windowLayout =
+                new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
+
+        info.windowLayout = windowLayout;
+        info.applicationInfo = new ApplicationInfo();
+        info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
+
+        // create starter.
+        final ActivityStarter optionStarter = prepareStarter();
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(launchBounds);
+
+        // run starter.
+        optionStarter
+                .setIntent(intent)
+                .setReason("testCreateTaskLayout")
+                .setActivityInfo(info)
+                .setActivityOptions(new SafeActivityOptions(options))
+                .execute();
+
+        // verify that values are passed to the modifier.
+        verify(modifier, times(1)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
+                any(), any());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 1195188..3041a5f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -101,6 +101,7 @@
     protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) {
         service = spy(service);
         doReturn(mock(IPackageManager.class)).when(service).getPackageManager();
+        doNothing().when(service).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
         service.mWindowManager = prepareMockWindowManager();
         return service;
     }
@@ -131,6 +132,11 @@
             return this;
         }
 
+        static ComponentName getDefaultComponent() {
+            return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+                    DEFAULT_COMPONENT_PACKAGE_NAME);
+        }
+
         ActivityBuilder setTask(TaskRecord task) {
             mTaskRecord = task;
             return this;
@@ -151,10 +157,6 @@
             return this;
         }
 
-        String getDefaultComponentPackageName() {
-            return DEFAULT_COMPONENT_PACKAGE_NAME;
-        }
-
         ActivityRecord build() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
@@ -371,7 +373,8 @@
 
         // Just return the current front task. This is called internally so we cannot use spy to mock this out.
         @Override
-        ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+        ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus,
+                boolean ignoreCurrent) {
             return mFocusedStack;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
new file mode 100644
index 0000000..c348e70
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.autofill;
+
+import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Map;
+
+@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() {
+        assertThat(getWhitelistedCompatModePackages(null)).isNull();
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_empty() {
+        assertThat(getWhitelistedCompatModePackages("")).isNull();
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
+        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
+    public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() {
+        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_onePackageOneUrl() {
+        final Map<String, String[]> result =
+                getWhitelistedCompatModePackages("one_is_the_loniest_package[url]");
+        assertThat(result).hasSize(1);
+        assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url");
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() {
+        final Map<String, String[]> result =
+                getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
+        assertThat(result).hasSize(1);
+        assertThat(result.get("one_is_the_loniest_package")).asList()
+            .containsExactly("4", "5", "8", "15", "16", "23", "42");
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
+        final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
+        assertThat(result).hasSize(1);
+        if (ADDS_DEFAULT_BUTTON) {
+            assertThat(result.get("one")).asList()
+                    .containsExactly("url_bar", "location_bar_edit_text");
+        } else {
+            assertThat(result.get("one")).isNull();
+        }
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() {
+        final Map<String, String[]> result =
+                getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
+        assertThat(result).hasSize(3);
+        assertThat(result.get("p1")).asList().containsExactly("p1u1");
+        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");
+    }
+
+    @Test
+    public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() {
+        final Map<String, String[]> result =
+                getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
+        assertThat(result).hasSize(2);
+        assertThat(result.get("p1")).asList().containsExactly("p1u1");
+        assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e864870..96f8160 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.LocalServices;
 
 import org.mockito.invocation.InvocationOnMock;
@@ -67,6 +68,7 @@
     private ArrayList<UserInfo> mPrimaryUserProfiles = new ArrayList<>();
 
     LockSettingsService mService;
+    LockSettingsInternal mLocalService;
 
     MockLockSettingsContext mContext;
     LockSettingsStorageTestable mStorage;
@@ -95,6 +97,7 @@
         mDevicePolicyManager = mock(DevicePolicyManager.class);
         mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);
 
+        LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
         LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
 
@@ -146,6 +149,7 @@
         // Adding a fake Device Owner app which will enable escrow token support in LSS.
         when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
                 new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
+        mLocalService = LocalServices.getService(LockSettingsInternal.class);
     }
 
     private UserInfo installChildProfile(int profileId) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 294c3e9..e9f9800 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -300,14 +300,14 @@
         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
-        assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
                 PRIMARY_USER_ID).getResponseCode();
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
-        mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+        mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
                 handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
 
         // Verify DPM gets notified about new device lock
@@ -329,16 +329,16 @@
         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
-        assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
                 0, PRIMARY_USER_ID).getResponseCode();
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
-        mService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, handle,
-                TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
-        mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+        mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+                handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+        mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
                 handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
 
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
@@ -355,18 +355,19 @@
         initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
-        assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
                 0, PRIMARY_USER_ID).getResponseCode();
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
                 PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
 
-        mService.setLockCredentialWithToken(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+        mLocalService.setLockCredentialWithToken(NEWPASSWORD,
+                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
 
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
@@ -378,8 +379,8 @@
             throws RemoteException {
         final String TOKEN = "some-high-entropy-secure-token";
         enableSyntheticPassword();
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
     }
@@ -388,8 +389,8 @@
             throws RemoteException {
         final String TOKEN = "some-high-entropy-secure-token";
         initializeCredentialUnderSP(null, PRIMARY_USER_ID);
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
     }
@@ -404,15 +405,15 @@
                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
         enableSyntheticPassword();
 
-        long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
         // Token not activated immediately since user password exists
-        assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         // Activate token (password gets migrated to SP at the same time)
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
                     .getResponseCode());
         // Verify token is activated
-        assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
     }
 
     public void testPasswordData_serializeDeserialize() {
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/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index 142041a..cfc7430 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -18,10 +18,13 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -149,4 +152,52 @@
 
         assertFalse(r.canShowBadge());
     }
+
+    @Test
+    public void testDndOverridesYes() {
+        BadgeExtractor extractor = new BadgeExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+        when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+        r.setIntercepted(true);
+        r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+        extractor.process(r);
+
+        assertFalse(r.canShowBadge());
+    }
+
+    @Test
+    public void testDndOConsidersInterception() {
+        BadgeExtractor extractor = new BadgeExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+        when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+        r.setIntercepted(false);
+        r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+        extractor.process(r);
+
+        assertTrue(r.canShowBadge());
+    }
+
+    @Test
+    public void testDndConsidersSuppressedVisualEffects() {
+        BadgeExtractor extractor = new BadgeExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+        when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+        r.setIntercepted(true);
+        r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
+
+        extractor.process(r);
+
+        assertTrue(r.canShowBadge());
+    }
 }
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/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7b2c040..4fe54b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -22,8 +22,19 @@
 import static android.app.NotificationManager.IMPORTANCE_MAX;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.os.Build.VERSION_CODES.O_MR1;
+import static android.os.Build.VERSION_CODES.P;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -2530,4 +2541,125 @@
         verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
                 anyInt(), anyInt());
     }
+
+    @Test
+    public void testSetNotificationPolicy_preP_setOldFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+        int expected = SUPPRESSED_EFFECT_BADGE
+                | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+                | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+                | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testSetNotificationPolicy_preP_setNewFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+
+        int expected = SUPPRESSED_EFFECT_BADGE;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testSetNotificationPolicy_preP_setOldNewFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+        int expected =
+                SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testSetNotificationPolicy_P_setOldFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+        int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+                | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+                | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testSetNotificationPolicy_P_setNewFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
+                        | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+        int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
+                | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
+                | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testSetNotificationPolicy_P_setOldNewFields() {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mService.mZenModeHelper = mZenModeHelper;
+        NotificationManager.Policy userPolicy =
+                new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+        NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+        int expected =  SUPPRESSED_EFFECT_STATUS_BAR;
+        int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+        assertEquals(expected, actual);
+
+        appPolicy = new NotificationManager.Policy(0, 0, 0,
+                SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
+                        | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+        expected =  SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
+                | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+        assertEquals(expected, actual);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
index faba6b6..beff0d1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
@@ -17,6 +17,8 @@
 package com.android.server.notification;
 
 import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -57,6 +59,8 @@
         assertFalse(r.isIntercepted());
 
         when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+                new NotificationManager.Policy(0,0,0));
 
         extractor.process(r);
 
@@ -70,7 +74,8 @@
         NotificationRecord r = generateRecord();
 
         when(mZenModeHelper.shouldIntercept(any())).thenReturn(false);
-        when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(false);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+                new NotificationManager.Policy(0,0,0));
 
         extractor.process(r);
 
@@ -84,13 +89,14 @@
         NotificationRecord r = generateRecord();
 
         when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
-        when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(true);
-        when(mZenModeHelper.shouldSuppressWhenScreenOn()).thenReturn(true);
+        when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+                new NotificationManager.Policy(0,0,0, SUPPRESSED_EFFECT_PEEK
+                        | SUPPRESSED_EFFECT_NOTIFICATION_LIST));
 
         extractor.process(r);
 
-        assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF
-                | NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON,
+        assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK
+                | NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
                 r.getSuppressedVisualEffects());
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
new file mode 100644
index 0000000..c0bd7cc
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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 distriZenbuted 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.notification;
+
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.media.AudioAttributes;
+import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenModeConfig;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.util.NotificationMessagingUtil;
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ZenModeFilteringTest extends UiServiceTestCase {
+
+    @Mock
+    private NotificationMessagingUtil mMessagingUtil;
+    private ZenModeFiltering mZenModeFiltering;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mZenModeFiltering = new ZenModeFiltering(mContext, mMessagingUtil);
+    }
+
+    private NotificationRecord getNotificationRecord() {
+        return getNotificationRecord(mock(NotificationChannel.class));
+    }
+
+    private NotificationRecord getNotificationRecord(NotificationChannel c) {
+        StatusBarNotification sbn = mock(StatusBarNotification.class);
+        when(sbn.getNotification()).thenReturn(mock(Notification.class));
+        return new NotificationRecord(mContext, sbn, c);
+    }
+
+    @Test
+    public void testIsMessage() {
+        NotificationRecord r = getNotificationRecord();
+
+        when(mMessagingUtil.isMessaging(any())).thenReturn(true);
+        assertTrue(mZenModeFiltering.isMessage(r));
+
+        when(mMessagingUtil.isMessaging(any())).thenReturn(false);
+        assertFalse(mZenModeFiltering.isMessage(r));
+    }
+
+    @Test
+    public void testIsAlarm() {
+        NotificationChannel c = mock(NotificationChannel.class);
+        when(c.getAudioAttributes()).thenReturn(new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_ALARM)
+                .build());
+        NotificationRecord r = getNotificationRecord(c);
+        assertTrue(mZenModeFiltering.isAlarm(r));
+
+        r = getNotificationRecord();
+        r.sbn.getNotification().category = Notification.CATEGORY_ALARM;
+        assertTrue(mZenModeFiltering.isAlarm(r));
+    }
+
+    @Test
+    public void testIsAlarm_wrongCategory() {
+        NotificationRecord r = getNotificationRecord();
+        r.sbn.getNotification().category = Notification.CATEGORY_CALL;
+        assertFalse(mZenModeFiltering.isAlarm(r));
+    }
+
+    @Test
+    public void testIsAlarm_wrongUsage() {
+        NotificationChannel c = mock(NotificationChannel.class);
+        when(c.getAudioAttributes()).thenReturn(new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+                .build());
+        NotificationRecord r = getNotificationRecord(c);
+        assertFalse(mZenModeFiltering.isAlarm(r));
+    }
+
+    @Test
+    public void testSuppressDNDInfo_yes_VisEffectsAllowed() {
+        NotificationRecord r = getNotificationRecord();
+        when(r.sbn.getPackageName()).thenReturn("android");
+        when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+        ZenModeConfig config = mock(ZenModeConfig.class);
+        config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects()
+                - SUPPRESSED_EFFECT_STATUS_BAR;
+
+        assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+    }
+
+    @Test
+    public void testSuppressDNDInfo_yes_WrongId() {
+        NotificationRecord r = getNotificationRecord();
+        when(r.sbn.getPackageName()).thenReturn("android");
+        when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION);
+        ZenModeConfig config = mock(ZenModeConfig.class);
+        config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+        assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+    }
+
+    @Test
+    public void testSuppressDNDInfo_yes_WrongPackage() {
+        NotificationRecord r = getNotificationRecord();
+        when(r.sbn.getPackageName()).thenReturn("android2");
+        when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+        ZenModeConfig config = mock(ZenModeConfig.class);
+        config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+        assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+    }
+
+    @Test
+    public void testSuppressDNDInfo_no() {
+        NotificationRecord r = getNotificationRecord();
+        when(r.sbn.getPackageName()).thenReturn("android");
+        when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+        ZenModeConfig config = mock(ZenModeConfig.class);
+        config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_ALARMS, config, r));
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_NO_INTERRUPTIONS, config, r));
+    }
+
+    @Test
+    public void testSuppressAnything_yes_ZenModeOff() {
+        NotificationRecord r = getNotificationRecord();
+        when(r.sbn.getPackageName()).thenReturn("bananas");
+        ZenModeConfig config = mock(ZenModeConfig.class);
+
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_OFF, config, r));
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 5bfa15a..9008803 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.TestCase.assertTrue;
@@ -34,6 +36,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.NotificationManager;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
@@ -48,8 +51,11 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.Xml;
 
+import com.android.internal.R;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
 import android.util.Slog;
 
@@ -58,6 +64,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -80,12 +93,27 @@
         mContext = spy(getContext());
         mContentResolver = mContext.getContentResolver();
         when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getString(R.string.zen_mode_default_every_night_name)).thenReturn("night");
+        when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
         when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
 
         mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
                 mConditionProviders));
     }
 
+    private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup)
+            throws Exception {
+        XmlSerializer serializer = new FastXmlSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        serializer.startDocument(null, true);
+        mZenModeHelperSpy.writeXml(serializer, forBackup);
+        serializer.endDocument();
+        serializer.flush();
+        mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
+        return baos;
+    }
+
     @Test
     public void testZenOff_NoMuteApplied() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
@@ -497,4 +525,71 @@
         verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
                 mZenModeHelperSpy.TAG);
     }
+
+    @Test
+    public void testParcelConfig() {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConfig.allowAlarms = false;
+        mZenModeHelperSpy.mConfig.allowMedia = false;
+        mZenModeHelperSpy.mConfig.allowSystem = false;
+        mZenModeHelperSpy.mConfig.allowReminders = true;
+        mZenModeHelperSpy.mConfig.allowCalls = true;
+        mZenModeHelperSpy.mConfig.allowMessages = true;
+        mZenModeHelperSpy.mConfig.allowEvents = true;
+        mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+        mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+        mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+        mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+        mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+        mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+        ZenModeConfig actual = mZenModeHelperSpy.mConfig.copy();
+
+        assertEquals(mZenModeHelperSpy.mConfig, actual);
+    }
+
+    @Test
+    public void testWriteXml() throws Exception {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConfig.allowAlarms = false;
+        mZenModeHelperSpy.mConfig.allowMedia = false;
+        mZenModeHelperSpy.mConfig.allowSystem = false;
+        mZenModeHelperSpy.mConfig.allowReminders = true;
+        mZenModeHelperSpy.mConfig.allowCalls = true;
+        mZenModeHelperSpy.mConfig.allowMessages = true;
+        mZenModeHelperSpy.mConfig.allowEvents = true;
+        mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+        mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+        mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+        mZenModeHelperSpy.mConfig.manualRule.zenMode =
+                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+        mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+        mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+        ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(false);
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(baos.toByteArray())), null);
+        parser.nextTag();
+        mZenModeHelperSpy.readXml(parser, false);
+
+        assertEquals(expected, mZenModeHelperSpy.mConfig);
+    }
+
+    @Test
+    public void testPolicyReadsSuppressedEffects() {
+        mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+        mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+        mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+
+        NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
+        assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a302578..9be9f3f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -506,6 +506,7 @@
             IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
 
             boolean checkin = false;
+            boolean compact = false;
             String pkg = null;
 
             if (args != null) {
@@ -513,6 +514,9 @@
                     String arg = args[i];
                     if ("--checkin".equals(arg)) {
                         checkin = true;
+                    } else
+                    if ("-c".equals(arg)) {
+                        compact = true;
                     } else if ("flush".equals(arg)) {
                         flushToDiskLocked();
                         pw.println("Flushed stats to disk");
@@ -534,7 +538,7 @@
                 if (checkin) {
                     mUserState.valueAt(i).checkin(idpw);
                 } else {
-                    mUserState.valueAt(i).dump(idpw, pkg);
+                    mUserState.valueAt(i).dump(idpw, pkg, compact);
                     idpw.println();
                 }
                 mAppStandby.dumpUser(idpw, userId, pkg);
@@ -986,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 29c5ee8..d974282 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -47,7 +47,7 @@
 class UserUsageStatsService {
     private static final String TAG = "UsageStatsService";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
-    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss");
+    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     private static final int sDateFormatFlags =
             DateUtils.FORMAT_SHOW_DATE
             | DateUtils.FORMAT_SHOW_TIME
@@ -516,25 +516,28 @@
         mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
             @Override
             public boolean checkin(IntervalStats stats) {
-                printIntervalStats(pw, stats, true, null);
+                printIntervalStats(pw, stats, false, false, null);
                 return true;
             }
         });
     }
 
     void dump(IndentingPrintWriter pw, String pkg) {
-        printLast24HrEvents(pw, true, pkg);
+        dump(pw, pkg, false);
+    }
+    void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
+        printLast24HrEvents(pw, !compact, pkg);
         for (int interval = 0; interval < mCurrentStats.length; interval++) {
             pw.print("In-memory ");
             pw.print(intervalToString(interval));
             pw.println(" stats");
-            printIntervalStats(pw, mCurrentStats[interval], false, pkg);
+            printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
         }
     }
 
     private String formatDateTime(long dateTime, boolean pretty) {
         if (pretty) {
-            return "\"" + DateFormat.format("yyyy-MM-dd HH:mm:ss", dateTime).toString() + "\"";
+            return "\"" + sDateFormat.format(dateTime)+ "\"";
         }
         return Long.toString(dateTime);
     }
@@ -623,8 +626,7 @@
     }
 
     void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
-            boolean checkin, String pkg) {
-        boolean prettyDates = !checkin;
+            boolean prettyDates, boolean skipEvents, String pkg) {
         if (prettyDates) {
             pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
                     stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
@@ -699,7 +701,7 @@
 
         // The last 24 hours of events is already printed in the non checkin dump
         // No need to repeat here.
-        if (checkin) {
+        if (!skipEvents) {
             pw.println("events");
             pw.increaseIndent();
             final TimeSparseArray<UsageEvents.Event> events = stats.events;
@@ -757,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/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 7cd16128..cac9f2b 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -30,6 +30,9 @@
         public static final int EUTRAN = 3;
         public static final int CDMA2000 = 4;
         public static final int IWLAN = 5;
+
+        /** @hide */
+        private AccessNetworkType() {};
     }
 
     /**
@@ -42,6 +45,9 @@
         public static final int WWAN = 1;
         /** Wireless Local Area Networks (i.e. Wifi) */
         public static final int WLAN = 2;
+
+        /** @hide */
+        private TransportType() {};
     }
 
     /**
@@ -63,6 +69,9 @@
         public static final int BAND_DCS1800 = 12;
         public static final int BAND_PCS1900 = 13;
         public static final int BAND_ER900 = 14;
+
+        /** @hide */
+        private GeranBand() {};
     }
 
     /**
@@ -92,6 +101,9 @@
         /** band 23, 24 are reserved */
         public static final int BAND_25 = 25;
         public static final int BAND_26 = 26;
+
+        /** @hide */
+        private UtranBand() {};
     }
 
     /**
@@ -147,6 +159,9 @@
         public static final int BAND_66 = 66;
         public static final int BAND_68 = 68;
         public static final int BAND_70 = 70;
+
+        /** @hide */
+        private EutranBand() {};
     }
 
     /**
@@ -179,5 +194,11 @@
         public static final int BAND_19 = 20;
         public static final int BAND_20 = 21;
         public static final int BAND_21 = 22;
+
+        /** @hide */
+        private CdmaBands() {};
     }
+
+    /** @hide */
+    private AccessNetworkConstants() {};
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d43db32..eebe2a1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1285,13 +1285,38 @@
 
     /**
      * The duration in seconds that platform call and message blocking is disabled after the user
-     * contacts emergency services. Platform considers values in the range 0 to 604800 (one week) as
-     * valid. See {@link android.provider.BlockedNumberContract#isBlocked(Context, String)}).
+     * contacts emergency services. Platform considers values for below cases:
+     *  1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly.
+     *  2) VALUE > 604800(one week): will use the default value as duration instead.
+     *  3) VALUE < 0: block will be disabled forever until user re-eanble block manually,
+     *     the suggested value to disable forever is -1.
+     * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)}
+     * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}.
      */
     public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT =
             "duration_blocking_disabled_after_emergency_int";
 
     /**
+     * Determines whether to enable enhanced call blocking feature on the device.
+     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
+     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
+     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
+     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+     *
+     * <p>
+     * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
+     *    and vendor.xml.
+     * <p>
+     * 2. For Dual SIM(DS) device, it should be customized in vendor.xml, since call blocking
+     *    function is used regardless of SIM.
+     * <p>
+     * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL =
+            "support_enhanced_call_blocking_bool";
+
+    /**
      * For carriers which require an empty flash to be sent before sending the normal 3-way calling
      * flash, the duration in milliseconds of the empty flash to send.  When {@code 0}, no empty
      * flash is sent.
@@ -2052,6 +2077,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index a277212..7f43ee5 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -29,9 +29,9 @@
 
 /**
  * The caller of
- * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)}
+ * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, Executor, NetworkScanCallback)}
  * will receive an instance of {@link NetworkScan}, which contains a callback method
- * {@link #stop()} for stopping the in-progress scan.
+ * {@link #stopScan()} for stopping the in-progress scan.
  */
 public class NetworkScan {
 
@@ -106,16 +106,24 @@
      * Use this method to stop an ongoing scan. When user requests a new scan, a {@link NetworkScan}
      * object will be returned, and the user can stop the scan by calling this method.
      */
-    public void stop() throws RemoteException {
+    public void stopScan() {
+        ITelephony telephony = getITelephony();
+        if (telephony == null) {
+            Rlog.e(TAG, "Failed to get the ITelephony instance.");
+        }
         try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                telephony.stopNetworkScan(mSubId, mScanId);
-            } else {
-                throw new RemoteException("Failed to get the ITelephony instance.");
-            }
+            telephony.stopNetworkScan(mSubId, mScanId);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "stopNetworkScan  RemoteException", ex);
+        }
+    }
+
+    /** @deprecated Use {@link #stopScan()} */
+    @Deprecated
+    public void stop() throws RemoteException {
+        try {
+            stopScan();
+        } catch (RuntimeException ex) {
             throw new RemoteException("Failed to stop the network scan with id " + mScanId);
         }
     }
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 af3a0bb..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;
@@ -34,6 +35,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.Handler;
@@ -52,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;
 
@@ -74,6 +75,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -1080,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.
@@ -1090,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).
      */
@@ -1112,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());
@@ -1144,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 {
@@ -1166,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
@@ -1190,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());
@@ -1200,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();
@@ -1218,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());
@@ -1227,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();
@@ -1245,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());
@@ -1749,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() {
@@ -1947,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
@@ -1966,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()));
@@ -2000,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());
@@ -2586,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());
@@ -2711,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());
@@ -2754,18 +2802,17 @@
      * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
      *         IMSI and IMPI. This includes the public key and the key identifier. This information
      *         will be stored in the device keystore. The system will return a null when no key was
-     *         found, and the carrier does not require a key. The system will throw the following
-     *         exceptions:
-     *         1. IllegalArgumentException when an invalid key is sent.
-     *         2. RuntimeException if the key is required but not found; and also if there was an
-     *         internal exception.
+     *         found, and the carrier does not require a key. The system will throw
+     *         IllegalArgumentException when an invalid key is sent or when key is required but
+     *         not found.
      * @hide
      */
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
-                throw new RuntimeException("IMSI error: Subscriber Info is null");
+                Rlog.e(TAG,"IMSI error: Subscriber Info is null");
+                return null;
             }
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
             if (keyType != KEY_TYPE_EPDG && keyType != KEY_TYPE_WLAN) {
@@ -2773,20 +2820,18 @@
             }
             ImsiEncryptionInfo imsiEncryptionInfo = info.getCarrierInfoForImsiEncryption(
                     subId, keyType, mContext.getOpPackageName());
-            if (imsiEncryptionInfo  == null
-                    && isImsiEncryptionRequired(subId, keyType)) {
+            if (imsiEncryptionInfo == null && isImsiEncryptionRequired(subId, keyType)) {
                 Rlog.e(TAG, "IMSI error: key is required but not found");
-                throw new RuntimeException("IMSI error: key is required but not found");
+                throw new IllegalArgumentException("IMSI error: key is required but not found");
             }
             return imsiEncryptionInfo;
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
-            throw new RuntimeException("IMSI error: Remote Exception");
         } catch (NullPointerException ex) {
             // This could happen before phone restarts due to crashing
             Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
-            throw new RuntimeException("IMSI error: Null Pointer exception");
         }
+        return null;
     }
 
     /**
@@ -2802,17 +2847,16 @@
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
-                throw new RuntimeException("IMSI error: Subscriber Info is null");
+                Rlog.e(TAG, "IMSI error: Subscriber Info is null");
+                return;
             }
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
             info.resetCarrierKeysForImsiEncryption(subId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
-            throw new RuntimeException("IMSI error: Remote Exception");
         } catch (NullPointerException ex) {
             // This could happen before phone restarts due to crashing
             Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
-            throw new RuntimeException("IMSI error: Null Pointer exception");
         }
     }
 
@@ -2879,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 {
@@ -2920,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,
@@ -2977,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
@@ -2994,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
@@ -3114,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());
@@ -3175,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.
@@ -3188,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.
@@ -3210,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
@@ -3275,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 {
@@ -3522,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
@@ -3543,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.
@@ -3552,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)
@@ -3570,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
@@ -3579,7 +3635,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @SystemApi
@@ -3592,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.
@@ -3602,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)
@@ -3620,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
@@ -3641,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.
      *
@@ -3651,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)
@@ -3670,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
@@ -3679,7 +3731,6 @@
      * @see #SIM_ACTIVATION_STATE_ACTIVATED
      * @see #SIM_ACTIVATION_STATE_DEACTIVATED
      * @see #SIM_ACTIVATION_STATE_RESTRICTED
-     * @see #hasCarrierPrivileges
      * @hide
      */
     @SystemApi
@@ -3692,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.
      *
@@ -3703,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)
@@ -3751,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());
@@ -3780,16 +3834,13 @@
     }
 
     /**
-     * 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
      *
      * @throws SecurityException if the caller does not have carrier privileges or is not the
      *         current default dialer
-     *
-     * @throws IllegalStateException if telephony service is unavailable.
      */
     public void sendDialerSpecialCode(String inputCode) {
         try {
@@ -3797,10 +3848,8 @@
             telephony.sendDialerSpecialCode(mContext.getOpPackageName(), inputCode);
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
-            ex.rethrowFromSystemServer();
         } catch (NullPointerException ex) {
             // This could happen before phone restarts due to crashing
-            throw new IllegalStateException("Telephony service unavailable");
         }
     }
 
@@ -4310,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.
@@ -4328,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).
@@ -4345,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.
@@ -4371,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.
@@ -4388,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
@@ -4414,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.
@@ -4441,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
@@ -4477,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.
@@ -4502,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.
@@ -4534,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
@@ -4554,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
@@ -4583,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
@@ -4601,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
@@ -4627,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.
@@ -4653,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.
@@ -4680,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.
@@ -4707,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.
@@ -4925,10 +4974,10 @@
         String v = android.provider.Settings.Global.getString(cr, name);
 
         if (index == Integer.MAX_VALUE) {
-            throw new RuntimeException("putIntAtIndex index == MAX_VALUE index=" + index);
+            throw new IllegalArgumentException("putIntAtIndex index == MAX_VALUE index=" + index);
         }
         if (index < 0) {
-            throw new RuntimeException("putIntAtIndex index < 0 index=" + index);
+            throw new IllegalArgumentException("putIntAtIndex index < 0 index=" + index);
         }
         if (v != null) {
             valArray = v.split(",");
@@ -5058,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
@@ -5067,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);
     }
@@ -5078,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}
@@ -5087,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) {
@@ -5109,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);
@@ -5316,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
@@ -5339,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 {
@@ -5359,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.
@@ -5391,33 +5443,46 @@
      * 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, TelephonyScanManager.NetworkScanCallback callback) {
+            NetworkScanRequest request, Executor executor,
+            TelephonyScanManager.NetworkScanCallback callback) {
         synchronized (this) {
             if (mTelephonyScanManager == null) {
                 mTelephonyScanManager = new TelephonyScanManager();
             }
         }
-        return mTelephonyScanManager.requestNetworkScan(getSubId(), request, callback);
+        return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback);
+    }
+
+    /**
+     * @deprecated
+     * Use {@link
+     * #requestNetworkScan(NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}
+     */
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public NetworkScan requestNetworkScan(
+        NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
+        return requestNetworkScan(request, AsyncTask.THREAD_POOL_EXECUTOR, callback);
     }
 
     /**
      * 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
@@ -5425,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 {
@@ -5444,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.
@@ -5471,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.
      */
@@ -5484,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
@@ -5576,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.
@@ -5594,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.
@@ -6249,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);
@@ -6294,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
@@ -6302,7 +6362,6 @@
      *
      * @return true if mobile data is enabled.
      *
-     * @see #hasCarrierPrivileges
      * @deprecated use {@link #isUserMobileDataEnabled()} instead.
      */
     @Deprecated
@@ -7073,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());
@@ -7119,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.
@@ -7164,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.
@@ -7192,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
@@ -7202,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) {
@@ -7210,24 +7273,23 @@
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
-            ex.rethrowAsRuntimeException();
         }
         return UNKNOWN_CARRIER_ID;
     }
 
     /**
-     * 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) {
@@ -7235,7 +7297,6 @@
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
-            ex.rethrowAsRuntimeException();
         }
         return null;
     }
@@ -7594,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) {
@@ -7617,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,
@@ -7759,7 +7816,6 @@
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
-            ex.rethrowAsRuntimeException();
         }
     }
 }
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index c182e34..946cecf 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -33,6 +33,7 @@
 import android.util.SparseArray;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import com.android.internal.telephony.ITelephony;
 
@@ -55,8 +56,10 @@
 
     /**
      * The caller of
-     * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
-     * implement and provide this callback so that the scan results or errors can be returned.
+     * {@link
+     * TelephonyManager#requestNetworkScan(NetworkScanRequest, Executor, NetworkScanCallback)}
+     * should implement and provide this callback so that the scan results or errors can be
+     * returned.
      */
     public static abstract class NetworkScanCallback {
         /** Returns the scan results to the user, this callback will be called multiple times. */
@@ -83,10 +86,13 @@
 
     private static class NetworkScanInfo {
         private final NetworkScanRequest mRequest;
+        private final Executor mExecutor;
         private final NetworkScanCallback mCallback;
 
-        NetworkScanInfo(NetworkScanRequest request, NetworkScanCallback callback) {
+        NetworkScanInfo(
+                NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
             mRequest = request;
+            mExecutor = executor;
             mCallback = callback;
         }
     }
@@ -112,10 +118,15 @@
                         "Failed to find NetworkScanInfo with id " + message.arg2);
                 }
                 NetworkScanCallback callback = nsi.mCallback;
+                Executor executor = nsi.mExecutor;
                 if (callback == null) {
                     throw new RuntimeException(
                         "Failed to find NetworkScanCallback with id " + message.arg2);
                 }
+                if (executor == null) {
+                    throw new RuntimeException(
+                        "Failed to find Executor with id " + message.arg2);
+                }
 
                 switch (message.what) {
                     case CALLBACK_SCAN_RESULTS:
@@ -126,21 +137,22 @@
                             for (int i = 0; i < parcelables.length; i++) {
                                 ci[i] = (CellInfo) parcelables[i];
                             }
-                            callback.onResults((List<CellInfo>) Arrays.asList(ci));
+                            executor.execute(() ->
+                                    callback.onResults((List<CellInfo>) Arrays.asList(ci)));
                         } catch (Exception e) {
                             Rlog.e(TAG, "Exception in networkscan callback onResults", e);
                         }
                         break;
                     case CALLBACK_SCAN_ERROR:
                         try {
-                            callback.onError(message.arg1);
+                            executor.execute(() -> callback.onError(message.arg1));
                         } catch (Exception e) {
                             Rlog.e(TAG, "Exception in networkscan callback onError", e);
                         }
                         break;
                     case CALLBACK_SCAN_COMPLETE:
                         try {
-                            callback.onComplete();
+                            executor.execute(() -> callback.onComplete());
                             mScanInfo.remove(message.arg2);
                         } catch (Exception e) {
                             Rlog.e(TAG, "Exception in networkscan callback onComplete", e);
@@ -171,12 +183,12 @@
      * @hide
      */
     public NetworkScan requestNetworkScan(int subId,
-            NetworkScanRequest request, NetworkScanCallback callback) {
+            NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder());
-                saveScanInfo(scanId, request, callback);
+                saveScanInfo(scanId, request, executor, callback);
                 return new NetworkScan(scanId, subId);
             }
         } catch (RemoteException ex) {
@@ -187,9 +199,10 @@
         return null;
     }
 
-    private void saveScanInfo(int id, NetworkScanRequest request, NetworkScanCallback callback) {
+    private void saveScanInfo(
+            int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
         synchronized (mScanInfo) {
-            mScanInfo.put(id, new NetworkScanInfo(request, callback));
+            mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
         }
     }
 
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 27e5f94..350dfe3 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -296,7 +296,10 @@
         readFromParcel(in);
     }
 
-    /** @hide */
+    /**
+     * Default Constructor that initializes the call profile with service type
+     * {@link #SERVICE_TYPE_NORMAL} and call type {@link #CALL_TYPE_VIDEO_N_VOICE}
+     */
     public ImsCallProfile() {
         mServiceType = SERVICE_TYPE_NORMAL;
         mCallType = CALL_TYPE_VOICE_N_VIDEO;
@@ -304,7 +307,25 @@
         mMediaProfile = new ImsStreamMediaProfile();
     }
 
-    /** @hide */
+    /**
+     * Constructor.
+     *
+     * @param serviceType the service type for the call. Can be one of the following:
+     *                    {@link #SERVICE_TYPE_NONE},
+     *                    {@link #SERVICE_TYPE_NORMAL},
+     *                    {@link #SERVICE_TYPE_EMERGENCY}
+     * @param callType the call type. Can be one of the following:
+     *                 {@link #CALL_TYPE_VOICE_N_VIDEO},
+     *                 {@link #CALL_TYPE_VOICE},
+     *                 {@link #CALL_TYPE_VIDEO_N_VOICE},
+     *                 {@link #CALL_TYPE_VT},
+     *                 {@link #CALL_TYPE_VT_TX},
+     *                 {@link #CALL_TYPE_VT_RX},
+     *                 {@link #CALL_TYPE_VT_NODIR},
+     *                 {@link #CALL_TYPE_VS},
+     *                 {@link #CALL_TYPE_VS_TX},
+     *                 {@link #CALL_TYPE_VS_RX}
+     */
     public ImsCallProfile(int serviceType, int callType) {
         mServiceType = serviceType;
         mCallType = callType;
@@ -312,6 +333,35 @@
         mMediaProfile = new ImsStreamMediaProfile();
     }
 
+    /**
+     * Constructor.
+     *
+     * @param serviceType the service type for the call. Can be one of the following:
+     *                    {@link #SERVICE_TYPE_NONE},
+     *                    {@link #SERVICE_TYPE_NORMAL},
+     *                    {@link #SERVICE_TYPE_EMERGENCY}
+     * @param callType the call type. Can be one of the following:
+     *                 {@link #CALL_TYPE_VOICE_N_VIDEO},
+     *                 {@link #CALL_TYPE_VOICE},
+     *                 {@link #CALL_TYPE_VIDEO_N_VOICE},
+     *                 {@link #CALL_TYPE_VT},
+     *                 {@link #CALL_TYPE_VT_TX},
+     *                 {@link #CALL_TYPE_VT_RX},
+     *                 {@link #CALL_TYPE_VT_NODIR},
+     *                 {@link #CALL_TYPE_VS},
+     *                 {@link #CALL_TYPE_VS_TX},
+     *                 {@link #CALL_TYPE_VS_RX}
+     * @param callExtras A bundle with the call extras.
+     * @param mediaProfile The IMS stream media profile.
+     */
+    public ImsCallProfile(int serviceType, int callType, Bundle callExtras,
+            ImsStreamMediaProfile mediaProfile) {
+        mServiceType = serviceType;
+        mCallType = callType;
+        mCallExtras = callExtras;
+        mMediaProfile = mediaProfile;
+    }
+
     public String getCallExtra(String name) {
         return getCallExtra(name, "");
     }
@@ -375,6 +425,16 @@
         mCallExtras = (Bundle) profile.mCallExtras.clone();
     }
 
+    /**
+     * Updates the media profile for the call.
+     *
+     * @param profile Call profile with new media profile.
+     */
+    public void updateMediaProfile(ImsCallProfile profile) {
+        mMediaProfile = profile.mMediaProfile;
+    }
+
+
     @Override
     public String toString() {
         return "{ serviceType=" + mServiceType +
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 243352b..137106a 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -99,6 +99,62 @@
         readFromParcel(in);
     }
 
+    /**
+     * Constructor.
+     *
+     * @param audioQuality The audio quality. Can be one of the following:
+     *                     {@link #AUDIO_QUALITY_AMR},
+     *                     {@link #AUDIO_QUALITY_AMR_WB},
+     *                     {@link #AUDIO_QUALITY_QCELP13K},
+     *                     {@link #AUDIO_QUALITY_EVRC},
+     *                     {@link #AUDIO_QUALITY_EVRC_B},
+     *                     {@link #AUDIO_QUALITY_EVRC_WB},
+     *                     {@link #AUDIO_QUALITY_EVRC_NW},
+     *                     {@link #AUDIO_QUALITY_GSM_EFR},
+     *                     {@link #AUDIO_QUALITY_GSM_FR},
+     *                     {@link #AUDIO_QUALITY_GSM_HR},
+     *                     {@link #AUDIO_QUALITY_G711U},
+     *                     {@link #AUDIO_QUALITY_G723},
+     *                     {@link #AUDIO_QUALITY_G711A},
+     *                     {@link #AUDIO_QUALITY_G722},
+     *                     {@link #AUDIO_QUALITY_G711AB},
+     *                     {@link #AUDIO_QUALITY_G729},
+     *                     {@link #AUDIO_QUALITY_EVS_NB},
+     *                     {@link #AUDIO_QUALITY_EVS_WB},
+     *                     {@link #AUDIO_QUALITY_EVS_SWB},
+     *                     {@link #AUDIO_QUALITY_EVS_FB},
+     * @param audioDirection The audio direction. Can be one of the following:
+     *                       {@link #DIRECTION_INVALID},
+     *                       {@link #DIRECTION_INACTIVE},
+     *                       {@link #DIRECTION_RECEIVE},
+     *                       {@link #DIRECTION_SEND},
+     *                       {@link #DIRECTION_SEND_RECEIVE},
+     * @param videoQuality The video quality. Can be one of the following:
+     *                     {@link #VIDEO_QUALITY_NONE},
+     *                     {@link #VIDEO_QUALITY_QCIF},
+     *                     {@link #VIDEO_QUALITY_QVGA_LANDSCAPE},
+     *                     {@link #VIDEO_QUALITY_QVGA_PORTRAIT},
+     *                     {@link #VIDEO_QUALITY_VGA_LANDSCAPE},
+     *                     {@link #VIDEO_QUALITY_VGA_PORTRAIT},
+     * @param videoDirection The video direction. Can be one of the following:
+     *                       {@link #DIRECTION_INVALID},
+     *                       {@link #DIRECTION_INACTIVE},
+     *                       {@link #DIRECTION_RECEIVE},
+     *                       {@link #DIRECTION_SEND},
+     *                       {@link #DIRECTION_SEND_RECEIVE},
+     * @param rttMode The rtt mode. Can be one of the following:
+     *                {@link #RTT_MODE_DISABLED},
+     *                {@link #RTT_MODE_FULL}
+     */
+    public ImsStreamMediaProfile(int audioQuality, int audioDirection,
+            int videoQuality, int videoDirection, int rttMode) {
+        mAudioQuality = audioQuality;
+        mAudioDirection = audioDirection;
+        mVideoQuality = videoQuality;
+        mVideoDirection = videoDirection;
+        mRttMode = rttMode;
+    }
+
     /** @hide */
     public ImsStreamMediaProfile() {
         mAudioQuality = AUDIO_QUALITY_NONE;
diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java
index 139939c..fc6b610 100644
--- a/telephony/java/com/android/internal/telephony/DcParamObject.java
+++ b/telephony/java/com/android/internal/telephony/DcParamObject.java
@@ -36,7 +36,7 @@
     }
 
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(mSubId);
+        dest.writeInt(mSubId);
     }
 
     private void readFromParcel(Parcel in) {
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/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 494ee65..f4b85b2 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -92,6 +92,7 @@
     private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
     private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
     private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+    private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save
     private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
     private static final String LAUNCH_FILE = "applaunch.txt";
     private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
@@ -263,6 +264,8 @@
                             String.format("killall -s SIGUSR1 %s", appPkgName);
                         getInstrumentation().getUiAutomation().executeShellCommand(
                             sendSignalCommand);
+                        // killall is async, wait one second to let the app save the profile.
+                        sleep(PROFILE_SAVE_SLEEP_TIMEOUT);
                         assertTrue(String.format("Not able to compile the app : %s", appPkgName),
                               compileApp(launch.getCompilerFilter(), appPkgName));
                     }
diff --git a/tests/OdmApps/Android.mk b/tests/OdmApps/Android.mk
new file mode 100644
index 0000000..64fa653
--- /dev/null
+++ b/tests/OdmApps/Android.mk
@@ -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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := OdmAppsTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_LIBRARIES := tradefed
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/OdmApps/AndroidTest.xml b/tests/OdmApps/AndroidTest.xml
new file mode 100644
index 0000000..2f12838
--- /dev/null
+++ b/tests/OdmApps/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for ODM apps test">
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="cleanup" value="true" />
+    <option name="remount-system" value="true" />
+    <option name="push" value="TestOdmApp.apk->/odm/app/TestOdmApp/TestOdmApp.apk" />
+    <option name="push" value="TestOdmPrivApp.apk->/odm/priv-app/TestOdmPrivApp/TestOdmPrivApp.apk" />
+    <option name="post-push" value="stop; start; sleep 5" />
+  </target_preparer>
+  <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+    <option name="jar" value="OdmAppsTest.jar" />
+  </test>
+</configuration>
diff --git a/tests/OdmApps/app/Android.mk b/tests/OdmApps/app/Android.mk
new file mode 100644
index 0000000..9eec0cc
--- /dev/null
+++ b/tests/OdmApps/app/Android.mk
@@ -0,0 +1,22 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/tests/OdmApps/app/AndroidManifest.xml b/tests/OdmApps/app/AndroidManifest.xml
new file mode 100755
index 0000000..84a9ea8
--- /dev/null
+++ b/tests/OdmApps/app/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.odm.app">
+</manifest>
+
diff --git a/tests/OdmApps/priv-app/Android.mk b/tests/OdmApps/priv-app/Android.mk
new file mode 100644
index 0000000..d423133
--- /dev/null
+++ b/tests/OdmApps/priv-app/Android.mk
@@ -0,0 +1,22 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmPrivApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/tests/OdmApps/priv-app/AndroidManifest.xml b/tests/OdmApps/priv-app/AndroidManifest.xml
new file mode 100755
index 0000000..031cf64
--- /dev/null
+++ b/tests/OdmApps/priv-app/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.odm.privapp">
+</manifest>
+
diff --git a/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
new file mode 100644
index 0000000..de742b8
--- /dev/null
+++ b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.odm.apps;
+
+import com.android.tradefed.testtype.DeviceTestCase;
+
+public class OdmAppsTest extends DeviceTestCase {
+    /**
+     * Test if /odm/app is working
+     */
+    public void testOdmApp() throws Exception {
+        assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.app"));
+    }
+
+    /**
+     * Test if /odm/priv-app is working
+     */
+    public void testOdmPrivApp() throws Exception {
+        assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.privapp"));
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ddcf327..93fa598 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2076,11 +2076,15 @@
     }
 
     /**
-     * Set the {@link ProxyInfo} for this WifiConfiguration.
+     * Set the {@link ProxyInfo} for this WifiConfiguration. This method should only be used by a
+     * device owner or profile owner. When other apps attempt to save a {@link WifiConfiguration}
+     * with modified proxy settings, the methods {@link WifiManager#addNetwork} and
+     * {@link WifiManager#updateNetwork} fail and return {@code -1}.
+     *
      * @param httpProxy {@link ProxyInfo} representing the httpProxy to be used by this
-     *                  WifiConfiguration. Setting this {@code null} will explicitly set no proxy,
-     *                  removing any proxy that was previously set.
-     * @exception throw IllegalArgumentException for invalid httpProxy
+     *                  WifiConfiguration. Setting this to {@code null} will explicitly set no
+     *                  proxy, removing any proxy that was previously set.
+     * @exception IllegalArgumentException for invalid httpProxy
      */
     public void setHttpProxy(ProxyInfo httpProxy) {
         if (httpProxy == null) {